From f7ce715ac449f37c3ee356725e209b0b838a9161 Mon Sep 17 00:00:00 2001 From: Fraser Date: Mon, 10 Jul 2023 21:59:51 -0400 Subject: [PATCH 1/4] create level modes --- api/chat.py | 29 ++++++++++++++++----- api/main.py | 3 ++- web/src/pages/index.tsx | 57 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/api/chat.py b/api/chat.py index 81dcae8..0547c91 100644 --- a/api/chat.py +++ b/api/chat.py @@ -48,7 +48,7 @@ def cap(text: str, max_tokens: int) -> str: -def construct_prompt(query: str, history: List[Dict[str, str]], context: List[Block]) -> List[Dict[str, str]]: +def construct_prompt(query: str, mode: str, history: List[Dict[str, str]], context: List[Block]) -> List[Dict[str, str]]: prompt = [] @@ -114,7 +114,22 @@ def construct_prompt(query: str, history: List[Dict[str, str]], context: List[Bl question_prompt = "In your answer, please cite any claims you make back to each source " \ "using the format: [a], [b], etc. If you use multiple sources to make a claim " \ - "cite all of them. For example: \"AGI is concerning [c, d, e].\"\n\nQ: " + query + "cite all of them. For example: \"AGI is concerning [c, d, e].\n\n" + + if mode == "crux": + question_prompt += "Answer very concisely, getting to the crux of the matter in as " \ + "few words as possible. Limit your answer to 1-2 sentences.\n\n" + + elif mode == "rookie": + question_prompt += "This user is new to the field of AI Alignment and Safety - don't " \ + "assume they know any technical terms or jargon. Still give a complete answer " \ + "without patronizing the user, but take any extra time needed to " \ + "explain new concepts or to illustrate your answer with examples.\n\n" + + elif mode != "default": raise ValueError("Invalid mode: " + mode) + + + question_prompt += "Q: " + query prompt.append({"role": "user", "content": question_prompt}) @@ -124,7 +139,7 @@ def construct_prompt(query: str, history: List[Dict[str, str]], context: List[Bl import time import json -def talk_to_robot_internal(index, query: str, history: List[Dict[str, str]], k: int = STANDARD_K, log: Callable = print): +def talk_to_robot_internal(index, query: str, mode: str, history: List[Dict[str, str]], k: int = STANDARD_K, log: Callable = print): try: # 1. Find the most relevant blocks from the Alignment Research Dataset yield {"state": "loading", "phase": "semantic"} @@ -134,7 +149,7 @@ def talk_to_robot_internal(index, query: str, history: List[Dict[str, str]], k: # 2. Generate a prompt yield {"state": "loading", "phase": "prompt"} - prompt = construct_prompt(query, history, top_k_blocks) + prompt = construct_prompt(query, mode, history, top_k_blocks) # 3. Count number of tokens left for completion (-50 for a buffer) max_tokens_completion = NUM_TOKENS - sum([len(ENCODER.encode(message["content"]) + ENCODER.encode(message["role"])) for message in prompt]) - 50 @@ -187,14 +202,14 @@ def talk_to_robot_internal(index, query: str, history: List[Dict[str, str]], k: yield {'state': 'error', 'error': str(e)} # convert talk_to_robot_internal from dict generator into json generator -def talk_to_robot(index, query: str, history: List[Dict[str, str]], k: int = STANDARD_K, log: Callable = print): - yield from (json.dumps(block) for block in talk_to_robot_internal(index, query, history, k, log)) +def talk_to_robot(index, query: str, mode: str, history: List[Dict[str, str]], k: int = STANDARD_K, log: Callable = print): + yield from (json.dumps(block) for block in talk_to_robot_internal(index, query, mode, history, k, log)) # wayyy simplified api def talk_to_robot_simple(index, query: str, log: Callable = print): res = {'response': ''} - for block in talk_to_robot_internal(index, query, [], log = log): + for block in talk_to_robot_internal(index, query, "default", [], log = log): if block['state'] == 'loading' and block['phase'] == 'semantic' and 'citations' in block: citations = {} for i, c in enumerate(block['citations']): diff --git a/api/main.py b/api/main.py index ec664b0..88c079e 100644 --- a/api/main.py +++ b/api/main.py @@ -41,9 +41,10 @@ def semantic(): def chat(): query = request.json['query'] + mode = request.json['mode'] history = request.json['history'] - return Response(stream(talk_to_robot(PINECONE_INDEX, query, history, log = log)), mimetype='text/event-stream') + return Response(stream(talk_to_robot(PINECONE_INDEX, query, mode, history, log = log)), mimetype='text/event-stream') # ------------- simplified non-streaming chat for internal testing ------------- diff --git a/web/src/pages/index.tsx b/web/src/pages/index.tsx index edce828..862b195 100644 --- a/web/src/pages/index.tsx +++ b/web/src/pages/index.tsx @@ -3,7 +3,7 @@ const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:3000"; import Head from "next/head"; import React from "react"; import { type NextPage } from "next"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import Image from 'next/image'; import Header from "../header"; @@ -236,6 +236,8 @@ type State = { response: AssistantEntry; }; +type Mode = "rookie" | "crux" | "default"; + // smooth-scroll to the bottom of the window if we're already less than 30% a screen away // note: finicky interaction with "smooth" - maybe fix later. @@ -250,6 +252,21 @@ const Home: NextPage = () => { const [ runningIndex, setRunningIndex ] = useState(0); const [ loadState, setLoadState ] = useState({state: "idle"}); + // [state, ready to save to localstorage] + const [ mode, setMode ] = useState<[Mode, boolean]>(["default", false]); + + // store mode in localstorage + useEffect(() => { + if (mode[1]) localStorage.setItem("chat_mode", mode[0]); + }, [mode]); + + // initial load + useEffect(() => { + const mode = localStorage.getItem("chat_mode") as Mode || "default"; + setMode([mode, true]); + }, []); + + const search = async ( query: string, query_source: "search" | "followups", @@ -281,7 +298,7 @@ const Home: NextPage = () => { "Allow-Control-Allow-Origin": "*" }, - body: JSON.stringify({query: query, history: + body: JSON.stringify({query: query, mode: mode[0], history: old_entries.filter((entry) => entry.role !== "error") .map((entry) => { return { @@ -428,7 +445,7 @@ const Home: NextPage = () => { const data = (await res.json()).data; setEntries([...new_entries, { - role: "stampy", + role: "stampy", content: data.text, url: "https://aisafety.info/?state=" + data.pageid, }]); @@ -447,7 +464,7 @@ const Home: NextPage = () => { enable((f_old: Followup[]) => { const f_old_filtered = f_old.filter((f) => f.pageid !== data.pageid && !fpids.has(f.pageid)); - return [...f_new, ...f_old_filtered].slice(0, MAX_FOLLOWUPS); // this is correct, it's N and not N-1 in javascript fsr + return [...f_new, ...f_old_filtered].slice(0, MAX_FOLLOWUPS); // this is correct, it's N and not N-1 in javascript fsr }); scroll30(); @@ -461,6 +478,38 @@ const Home: NextPage = () => {
+ {/* three buttons for the three modes, place far right, 1rem between each */} +
+ + // + + // + +
+ + + + +
    {entries.map((entry, i) => { From 8303bf196e99bd8590f9e80f73a80da1f3120c6f Mon Sep 17 00:00:00 2001 From: Fraser Date: Mon, 10 Jul 2023 22:06:30 -0400 Subject: [PATCH 2/4] Add plex suggestion --- api/chat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/chat.py b/api/chat.py index 0547c91..3afabec 100644 --- a/api/chat.py +++ b/api/chat.py @@ -124,7 +124,9 @@ def construct_prompt(query: str, mode: str, history: List[Dict[str, str]], conte question_prompt += "This user is new to the field of AI Alignment and Safety - don't " \ "assume they know any technical terms or jargon. Still give a complete answer " \ "without patronizing the user, but take any extra time needed to " \ - "explain new concepts or to illustrate your answer with examples.\n\n" + "explain new concepts or to illustrate your answer with examples. "\ + "Put extra effort into explaining the intuition behind concepts " \ + "rather than just giving a formal definition.\n\n" elif mode != "default": raise ValueError("Invalid mode: " + mode) From df40ca4e1dc521910a60ff4cb417326e589c04a9 Mon Sep 17 00:00:00 2001 From: FraserLee <30442265+FraserLee@users.noreply.github.com> Date: Tue, 11 Jul 2023 23:25:42 -0400 Subject: [PATCH 3/4] Implement changes from @henri123lemoine review --- api/chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/chat.py b/api/chat.py index 3afabec..17deb91 100644 --- a/api/chat.py +++ b/api/chat.py @@ -114,7 +114,7 @@ def construct_prompt(query: str, mode: str, history: List[Dict[str, str]], conte question_prompt = "In your answer, please cite any claims you make back to each source " \ "using the format: [a], [b], etc. If you use multiple sources to make a claim " \ - "cite all of them. For example: \"AGI is concerning [c, d, e].\n\n" + "cite all of them. For example: \"AGI is concerning [c, d, e].\"\n\n" if mode == "crux": question_prompt += "Answer very concisely, getting to the crux of the matter in as " \ From 7558dbbfa9274fa0a79443aa50eb0703cd5eb320 Mon Sep 17 00:00:00 2001 From: Fraser Date: Tue, 11 Jul 2023 23:32:16 -0400 Subject: [PATCH 4/4] implement changes from @Thomas-Lemoine review --- api/chat.py | 2 +- web/src/pages/index.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/chat.py b/api/chat.py index 17deb91..db32d46 100644 --- a/api/chat.py +++ b/api/chat.py @@ -116,7 +116,7 @@ def construct_prompt(query: str, mode: str, history: List[Dict[str, str]], conte "using the format: [a], [b], etc. If you use multiple sources to make a claim " \ "cite all of them. For example: \"AGI is concerning [c, d, e].\"\n\n" - if mode == "crux": + if mode == "concise": question_prompt += "Answer very concisely, getting to the crux of the matter in as " \ "few words as possible. Limit your answer to 1-2 sentences.\n\n" diff --git a/web/src/pages/index.tsx b/web/src/pages/index.tsx index 862b195..9d4808c 100644 --- a/web/src/pages/index.tsx +++ b/web/src/pages/index.tsx @@ -236,7 +236,7 @@ type State = { response: AssistantEntry; }; -type Mode = "rookie" | "crux" | "default"; +type Mode = "rookie" | "concise" | "default"; // smooth-scroll to the bottom of the window if we're already less than 30% a screen away @@ -491,11 +491,11 @@ const Home: NextPage = () => { // //