T-Flet commited on
Commit
e17df50
β€’
1 Parent(s): e6fc81a

Switched to Gradio; much more convenient AND much better results.

Browse files
Dockerfile DELETED
@@ -1,17 +0,0 @@
1
- FROM python:3.11.7
2
-
3
- # Set up a new user named "user" with user ID 1000
4
- RUN useradd -m -u 1000 user
5
-
6
- # Switch to the "user" user
7
- USER user
8
-
9
- COPY . .
10
-
11
- WORKDIR /
12
-
13
- RUN pip install --no-cache-dir --upgrade -r /requirements.txt
14
-
15
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
16
-
17
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,15 +1,18 @@
1
  ---
2
  title: Star-Wars-Expert
3
  colorFrom: yellow
4
- colorTo: yellow
5
- sdk: docker
6
  app_file: app.py
7
  pinned: false
 
8
  ---
9
 
10
  # Star-Wars-Expert
11
- A LLM with RAG making it knowledgeable about Star Wars plot and data.
12
 
 
 
 
13
 
14
 
15
  ## Data
 
1
  ---
2
  title: Star-Wars-Expert
3
  colorFrom: yellow
4
+ colorTo: blue
5
+ sdk: gradio
6
  app_file: app.py
7
  pinned: false
8
+ license: mit
9
  ---
10
 
11
  # Star-Wars-Expert
 
12
 
13
+ A LLM with RAG making it knowledgeable about Star Wars lore (built with LangChain, GPT-3.5 and Gradio).
14
+
15
+ Chat with it [on its Huggingface space](https://huggingface.co/spaces/T-Flet/Star-Wars-Expert) (or clone the repo and `python app.py`).
16
 
17
 
18
  ## Data
app.py CHANGED
@@ -1,71 +1,34 @@
1
- # Chains
2
- from langchain_core.pydantic_v1 import BaseModel, Field
3
 
4
- # To serve the app
5
- from fastapi import FastAPI
6
- from langchain_core.messages import BaseMessage
7
- from langserve import add_routes, CustomUserType
8
 
 
9
  import dotenv
10
  dotenv.load_dotenv()
11
 
 
12
  from ingredients import script_db, woo_db, full_chain, compound_chain, agent_executor
13
 
14
 
 
 
 
 
 
 
 
 
15
 
16
- ## Type specifications (with unusual class-scope fields)
17
 
18
- class StrInput(BaseModel):
19
- input: str
20
 
21
- class Input(BaseModel):
22
- input: str
23
- chat_history: list[BaseMessage] = Field(
24
- ...,
25
- extra = dict(widget = dict(type = 'chat', input = 'location')),
26
- )
27
-
28
- class Output(BaseModel):
29
- output: str
30
-
31
-
32
-
33
- ## App definition
34
- # NOTE: The chat playground type has a web page issue (flashes and becomes white, hence non-interactable; this was supposedly solved in an issue late last year)
35
-
36
- app = FastAPI(
37
- title = 'Star Wars Expert',
38
- version = '1.0',
39
- description = 'A Star Wars expert chatbot',
40
- )
41
-
42
-
43
- # Basic retriever versions
44
-
45
- # add_routes(app, script_db.as_retriever())
46
- # add_routes(app, woo_db.as_retriever())
47
-
48
-
49
- # History-aware retriever version
50
- # add_routes(app, full_chain.with_types(input_type = StrInput, output_type = Output), playground_type = 'default')
51
-
52
-
53
- # Agent version
54
-
55
- # add_routes(app, agent_executor, playground_type = 'chat')
56
- # add_routes(app, agent_executor.with_types(input_type = StrInput, output_type = Output))
57
-
58
-
59
- # Non-agent chain-logic version
60
-
61
- add_routes(app, compound_chain.with_types(input_type = StrInput))
62
- # add_routes(app, compound_chain.with_types(input_type = Input), playground_type = 'chat')
63
-
64
-
65
-
66
- if __name__ == '__main__':
67
- import uvicorn
68
-
69
- uvicorn.run(app, host = 'localhost', port = 8000)
70
 
71
 
 
1
+ from langchain_core.messages import HumanMessage, AIMessage
 
2
 
3
+ import gradio as gr
 
 
 
4
 
5
+ # For local testing; not used in the Huggingface space
6
  import dotenv
7
  dotenv.load_dotenv()
8
 
9
+ # The available backends to use in the app
10
  from ingredients import script_db, woo_db, full_chain, compound_chain, agent_executor
11
 
12
 
13
+ def chat(message, history):
14
+ formatted_history = []
15
+ for human, ai in history:
16
+ formatted_history.append(HumanMessage(content = human))
17
+ formatted_history.append(AIMessage(content = ai))
18
+
19
+ # Yes, the context chat entries are not fed back to the system, but that is probably for the best due to input size limit
20
+ response = compound_chain.invoke(dict(input = HumanMessage(content = message), chat_history = formatted_history))
21
 
22
+ return response['answer']
23
 
 
 
24
 
25
+ gr.ChatInterface(
26
+ chat,
27
+ textbox = gr.Textbox(placeholder = 'Ask something about Star Wars', container = False, scale = 7),
28
+ title = 'Star Wars Expert', description = 'I am knowledgeable about Star Wars; ask me about it',
29
+ examples = ['Do you know the tragedy of Darth Plagueis the Wise?', 'What power source did the Death Star use?', "Who participates in Han's rescue from Jabba? And where is the palace?"],
30
+ cache_examples = False, # This would avoid invoking the chatbot for the example queries (it would invokes it on them on startup instead)
31
+ theme = 'soft', retry_btn = None, undo_btn = 'Delete Previous', clear_btn = 'Clear'
32
+ ).launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
 
app_notebook.ipynb DELETED
@@ -1,69 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 5,
6
- "metadata": {},
7
- "outputs": [],
8
- "source": [
9
- "from langserve import RemoteRunnable\n",
10
- "\n",
11
- "remote_runnable = RemoteRunnable('http://localhost:8000/')"
12
- ]
13
- },
14
- {
15
- "cell_type": "code",
16
- "execution_count": 7,
17
- "metadata": {},
18
- "outputs": [
19
- {
20
- "ename": "HTTPStatusError",
21
- "evalue": "Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 for Internal Server Error",
22
- "output_type": "error",
23
- "traceback": [
24
- "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
25
- "\u001b[1;31mHTTPStatusError\u001b[0m Traceback (most recent call last)",
26
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langserve\\client.py:157\u001b[0m, in \u001b[0;36m_raise_for_status\u001b[1;34m(response)\u001b[0m\n\u001b[0;32m 156\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 157\u001b[0m \u001b[43mresponse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 158\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mHTTPStatusError \u001b[38;5;28;01mas\u001b[39;00m e:\n",
27
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\httpx\\_models.py:761\u001b[0m, in \u001b[0;36mResponse.raise_for_status\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 760\u001b[0m message \u001b[38;5;241m=\u001b[39m message\u001b[38;5;241m.\u001b[39mformat(\u001b[38;5;28mself\u001b[39m, error_type\u001b[38;5;241m=\u001b[39merror_type)\n\u001b[1;32m--> 761\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m HTTPStatusError(message, request\u001b[38;5;241m=\u001b[39mrequest, response\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n",
28
- "\u001b[1;31mHTTPStatusError\u001b[0m: Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500",
29
- "\nDuring handling of the above exception, another exception occurred:\n",
30
- "\u001b[1;31mHTTPStatusError\u001b[0m Traceback (most recent call last)",
31
- "Cell \u001b[1;32mIn[7], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mremote_runnable\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mDo you know the tragedy of Darth Plagueis the Wise?\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;66;03m# remote_runnable.invoke(dict(input = 'Do you know the tragedy of Darth Plagueis the Wise?', chat_history = []))\u001b[39;00m\n",
32
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langserve\\client.py:356\u001b[0m, in \u001b[0;36mRemoteRunnable.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m 354\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs:\n\u001b[0;32m 355\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mkwargs not implemented yet.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 356\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_invoke\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n",
33
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langchain_core\\runnables\\base.py:1625\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[1;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[0;32m 1621\u001b[0m context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[0;32m 1622\u001b[0m context\u001b[38;5;241m.\u001b[39mrun(var_child_runnable_config\u001b[38;5;241m.\u001b[39mset, child_config)\n\u001b[0;32m 1623\u001b[0m output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[0;32m 1624\u001b[0m Output,\n\u001b[1;32m-> 1625\u001b[0m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1626\u001b[0m \u001b[43m \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m 1627\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m 1628\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[0;32m 1629\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1630\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1631\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1632\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[0;32m 1633\u001b[0m )\n\u001b[0;32m 1634\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m 1635\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
34
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langchain_core\\runnables\\config.py:347\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[1;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[0;32m 345\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[0;32m 346\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[1;32m--> 347\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
35
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langserve\\client.py:343\u001b[0m, in \u001b[0;36mRemoteRunnable._invoke\u001b[1;34m(self, input, run_manager, config, **kwargs)\u001b[0m\n\u001b[0;32m 334\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Invoke the runnable with the given input and config.\"\"\"\u001b[39;00m\n\u001b[0;32m 335\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msync_client\u001b[38;5;241m.\u001b[39mpost(\n\u001b[0;32m 336\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/invoke\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 337\u001b[0m json\u001b[38;5;241m=\u001b[39m{\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 341\u001b[0m },\n\u001b[0;32m 342\u001b[0m )\n\u001b[1;32m--> 343\u001b[0m output, callback_events \u001b[38;5;241m=\u001b[39m \u001b[43m_decode_response\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 344\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_lc_serializer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mis_batch\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\n\u001b[0;32m 345\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_use_server_callback_events \u001b[38;5;129;01mand\u001b[39;00m callback_events:\n\u001b[0;32m 348\u001b[0m handle_callbacks(run_manager, callback_events)\n",
36
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langserve\\client.py:230\u001b[0m, in \u001b[0;36m_decode_response\u001b[1;34m(serializer, response, is_batch)\u001b[0m\n\u001b[0;32m 223\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_decode_response\u001b[39m(\n\u001b[0;32m 224\u001b[0m serializer: Serializer,\n\u001b[0;32m 225\u001b[0m response: httpx\u001b[38;5;241m.\u001b[39mResponse,\n\u001b[0;32m 226\u001b[0m \u001b[38;5;241m*\u001b[39m,\n\u001b[0;32m 227\u001b[0m is_batch: \u001b[38;5;28mbool\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[0;32m 228\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tuple[Any, Union[List[CallbackEventDict], List[List[CallbackEventDict]]]]:\n\u001b[0;32m 229\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Decode the response.\"\"\"\u001b[39;00m\n\u001b[1;32m--> 230\u001b[0m \u001b[43m_raise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 231\u001b[0m obj \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mjson()\n\u001b[0;32m 232\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(obj, \u001b[38;5;28mdict\u001b[39m):\n",
37
- "File \u001b[1;32mc:\\Users\\Dr-Lo\\miniconda3\\envs\\ML11\\Lib\\site-packages\\langserve\\client.py:165\u001b[0m, in \u001b[0;36m_raise_for_status\u001b[1;34m(response)\u001b[0m\n\u001b[0;32m 162\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext:\n\u001b[0;32m 163\u001b[0m message \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m for \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m--> 165\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mHTTPStatusError(\n\u001b[0;32m 166\u001b[0m message\u001b[38;5;241m=\u001b[39mmessage,\n\u001b[0;32m 167\u001b[0m request\u001b[38;5;241m=\u001b[39m_sanitize_request(e\u001b[38;5;241m.\u001b[39mrequest),\n\u001b[0;32m 168\u001b[0m response\u001b[38;5;241m=\u001b[39me\u001b[38;5;241m.\u001b[39mresponse,\n\u001b[0;32m 169\u001b[0m )\n",
38
- "\u001b[1;31mHTTPStatusError\u001b[0m: Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 for Internal Server Error"
39
- ]
40
- }
41
- ],
42
- "source": [
43
- "remote_runnable.invoke(dict(input = 'Do you know the tragedy of Darth Plagueis the Wise?', chat_history = []))\n",
44
- "# remote_runnable.invoke(dict(input = 'What power source did the Death Star use?', chat_history = []))"
45
- ]
46
- }
47
- ],
48
- "metadata": {
49
- "kernelspec": {
50
- "display_name": "ML11",
51
- "language": "python",
52
- "name": "python3"
53
- },
54
- "language_info": {
55
- "codemirror_mode": {
56
- "name": "ipython",
57
- "version": 3
58
- },
59
- "file_extension": ".py",
60
- "mimetype": "text/x-python",
61
- "name": "python",
62
- "nbconvert_exporter": "python",
63
- "pygments_lexer": "ipython3",
64
- "version": "3.11.7"
65
- }
66
- },
67
- "nbformat": 4,
68
- "nbformat_minor": 2
69
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
explore.ipynb CHANGED
@@ -61,6 +61,7 @@
61
  "\n",
62
  "import os\n",
63
  "import shutil\n",
 
64
  "import re\n",
65
  "\n",
66
  "import dotenv\n",
@@ -91,7 +92,8 @@
91
  "name": "stdout",
92
  "output_type": "stream",
93
  "text": [
94
- "The script database contains 1251 chunks, with mean length of 895 characters\n"
 
95
  ]
96
  }
97
  ],
@@ -106,7 +108,7 @@
106
  "\n",
107
  "REGENERATE_SCRIPT_DATABASE = False\n",
108
  "\n",
109
- "if (db_exists := os.path.exists(db_dir := r'scripts\\db')):\n",
110
  " if REGENERATE_SCRIPT_DATABASE:\n",
111
  " print('Deleting the previous database and creating a new one (because otherwise content is duplicated in the db every time this block is run)')\n",
112
  " shutil.rmtree(db_dir)\n",
@@ -114,7 +116,7 @@
114
  "\n",
115
  "if not db_exists or (db_exists and REGENERATE_SCRIPT_DATABASE): # Unfortunate disjoining of the two conditional blocks\n",
116
  " scripts = DirectoryLoader('scripts', glob = '*.txt', loader_cls = TextLoader).load()\n",
117
- " for s in scripts: s.page_content = re.sub(r'\\t+|[ ]{2,}', '', s.page_content) # Spacing to centre text noise\n",
118
  "\n",
119
  " script_chunks = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200, separators = ['\\n\\n\\n', '\\n\\n', '\\n']).split_documents(scripts)\n",
120
  " # Why not some overlap for extra context just in case?\n",
@@ -588,7 +590,7 @@
588
  "source": [
589
  "REGENERATE_WOOKIEEPEDIA_DATABASE = False\n",
590
  "\n",
591
- "if (db_exists := os.path.exists(db_dir := r'wookieepedia\\db')):\n",
592
  " if REGENERATE_WOOKIEEPEDIA_DATABASE:\n",
593
  " print('Deleting the previous database and creating a new one (because otherwise content is duplicated in the db every time this block is run)')\n",
594
  " shutil.rmtree(db_dir)\n",
@@ -732,9 +734,164 @@
732
  },
733
  {
734
  "cell_type": "code",
735
- "execution_count": null,
736
  "metadata": {},
737
- "outputs": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
738
  "source": [
739
  "# from sentence_transformers import SentenceTransformer\n",
740
  "\n",
@@ -1196,7 +1353,7 @@
1196
  "source": [
1197
  "compound_chain = create_retrieval_chain(compound_retriever, document_chain)\n",
1198
  "\n",
1199
- "compound_chain.invoke(dict(input = 'Do you know the tragedy of Darth Plagueis the Wise?'))"
1200
  ]
1201
  }
1202
  ],
 
61
  "\n",
62
  "import os\n",
63
  "import shutil\n",
64
+ "from pathlib import Path\n",
65
  "import re\n",
66
  "\n",
67
  "import dotenv\n",
 
92
  "name": "stdout",
93
  "output_type": "stream",
94
  "text": [
95
+ "Deleting the previous database and creating a new one (because otherwise content is duplicated in the db every time this block is run)\n",
96
+ "The script database contains 1260 chunks, with mean length of 892 characters\n"
97
  ]
98
  }
99
  ],
 
108
  "\n",
109
  "REGENERATE_SCRIPT_DATABASE = False\n",
110
  "\n",
111
+ "if (db_exists := os.path.exists(db_dir := str(Path('scripts') / 'db')):\n",
112
  " if REGENERATE_SCRIPT_DATABASE:\n",
113
  " print('Deleting the previous database and creating a new one (because otherwise content is duplicated in the db every time this block is run)')\n",
114
  " shutil.rmtree(db_dir)\n",
 
116
  "\n",
117
  "if not db_exists or (db_exists and REGENERATE_SCRIPT_DATABASE): # Unfortunate disjoining of the two conditional blocks\n",
118
  " scripts = DirectoryLoader('scripts', glob = '*.txt', loader_cls = TextLoader).load()\n",
119
+ " for s in scripts: s.page_content = re.sub(r'^[\\t ]+', '', s.page_content, flags = re.MULTILINE) # Spacing to centre text noise\n",
120
  "\n",
121
  " script_chunks = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200, separators = ['\\n\\n\\n', '\\n\\n', '\\n']).split_documents(scripts)\n",
122
  " # Why not some overlap for extra context just in case?\n",
 
590
  "source": [
591
  "REGENERATE_WOOKIEEPEDIA_DATABASE = False\n",
592
  "\n",
593
+ "if (db_exists := os.path.exists(db_dir := str(Path('wookieepedia') / 'db'))):\n",
594
  " if REGENERATE_WOOKIEEPEDIA_DATABASE:\n",
595
  " print('Deleting the previous database and creating a new one (because otherwise content is duplicated in the db every time this block is run)')\n",
596
  " shutil.rmtree(db_dir)\n",
 
734
  },
735
  {
736
  "cell_type": "code",
737
+ "execution_count": 7,
738
  "metadata": {},
739
+ "outputs": [
740
+ {
741
+ "data": {
742
+ "application/vnd.jupyter.widget-view+json": {
743
+ "model_id": "da3292f4ae9e4d6c912f226b91a4412e",
744
+ "version_major": 2,
745
+ "version_minor": 0
746
+ },
747
+ "text/plain": [
748
+ "modules.json: 0%| | 0.00/349 [00:00<?, ?B/s]"
749
+ ]
750
+ },
751
+ "metadata": {},
752
+ "output_type": "display_data"
753
+ },
754
+ {
755
+ "data": {
756
+ "application/vnd.jupyter.widget-view+json": {
757
+ "model_id": "2f3dcddcf3ce4fbbac71999124541281",
758
+ "version_major": 2,
759
+ "version_minor": 0
760
+ },
761
+ "text/plain": [
762
+ "config_sentence_transformers.json: 0%| | 0.00/116 [00:00<?, ?B/s]"
763
+ ]
764
+ },
765
+ "metadata": {},
766
+ "output_type": "display_data"
767
+ },
768
+ {
769
+ "data": {
770
+ "application/vnd.jupyter.widget-view+json": {
771
+ "model_id": "70c10212924a487d878d8f87c43bdd90",
772
+ "version_major": 2,
773
+ "version_minor": 0
774
+ },
775
+ "text/plain": [
776
+ "README.md: 0%| | 0.00/10.7k [00:00<?, ?B/s]"
777
+ ]
778
+ },
779
+ "metadata": {},
780
+ "output_type": "display_data"
781
+ },
782
+ {
783
+ "data": {
784
+ "application/vnd.jupyter.widget-view+json": {
785
+ "model_id": "8d04da9721ec4e86b01068d16a8588fa",
786
+ "version_major": 2,
787
+ "version_minor": 0
788
+ },
789
+ "text/plain": [
790
+ "sentence_bert_config.json: 0%| | 0.00/53.0 [00:00<?, ?B/s]"
791
+ ]
792
+ },
793
+ "metadata": {},
794
+ "output_type": "display_data"
795
+ },
796
+ {
797
+ "data": {
798
+ "application/vnd.jupyter.widget-view+json": {
799
+ "model_id": "8dfd7c22b7a44ea9a16fbd6573635186",
800
+ "version_major": 2,
801
+ "version_minor": 0
802
+ },
803
+ "text/plain": [
804
+ "config.json: 0%| | 0.00/612 [00:00<?, ?B/s]"
805
+ ]
806
+ },
807
+ "metadata": {},
808
+ "output_type": "display_data"
809
+ },
810
+ {
811
+ "data": {
812
+ "application/vnd.jupyter.widget-view+json": {
813
+ "model_id": "f5fabe250679451da00677c57d08abf1",
814
+ "version_major": 2,
815
+ "version_minor": 0
816
+ },
817
+ "text/plain": [
818
+ "model.safetensors: 0%| | 0.00/90.9M [00:00<?, ?B/s]"
819
+ ]
820
+ },
821
+ "metadata": {},
822
+ "output_type": "display_data"
823
+ },
824
+ {
825
+ "data": {
826
+ "application/vnd.jupyter.widget-view+json": {
827
+ "model_id": "0e978ece6930478b9e7106020bfa1ebf",
828
+ "version_major": 2,
829
+ "version_minor": 0
830
+ },
831
+ "text/plain": [
832
+ "tokenizer_config.json: 0%| | 0.00/350 [00:00<?, ?B/s]"
833
+ ]
834
+ },
835
+ "metadata": {},
836
+ "output_type": "display_data"
837
+ },
838
+ {
839
+ "data": {
840
+ "application/vnd.jupyter.widget-view+json": {
841
+ "model_id": "db27fca31ec844e888ed7f6f6aecbe2b",
842
+ "version_major": 2,
843
+ "version_minor": 0
844
+ },
845
+ "text/plain": [
846
+ "vocab.txt: 0%| | 0.00/232k [00:00<?, ?B/s]"
847
+ ]
848
+ },
849
+ "metadata": {},
850
+ "output_type": "display_data"
851
+ },
852
+ {
853
+ "data": {
854
+ "application/vnd.jupyter.widget-view+json": {
855
+ "model_id": "d1570b2dd7d7413ba72777799fa7e2a5",
856
+ "version_major": 2,
857
+ "version_minor": 0
858
+ },
859
+ "text/plain": [
860
+ "tokenizer.json: 0%| | 0.00/466k [00:00<?, ?B/s]"
861
+ ]
862
+ },
863
+ "metadata": {},
864
+ "output_type": "display_data"
865
+ },
866
+ {
867
+ "data": {
868
+ "application/vnd.jupyter.widget-view+json": {
869
+ "model_id": "2ec46385e4f44907991e3f498bc4b77d",
870
+ "version_major": 2,
871
+ "version_minor": 0
872
+ },
873
+ "text/plain": [
874
+ "special_tokens_map.json: 0%| | 0.00/112 [00:00<?, ?B/s]"
875
+ ]
876
+ },
877
+ "metadata": {},
878
+ "output_type": "display_data"
879
+ },
880
+ {
881
+ "data": {
882
+ "application/vnd.jupyter.widget-view+json": {
883
+ "model_id": "0f1dddc6b2ee4ebf8eb37e356b9c3e41",
884
+ "version_major": 2,
885
+ "version_minor": 0
886
+ },
887
+ "text/plain": [
888
+ "1_Pooling/config.json: 0%| | 0.00/190 [00:00<?, ?B/s]"
889
+ ]
890
+ },
891
+ "metadata": {},
892
+ "output_type": "display_data"
893
+ }
894
+ ],
895
  "source": [
896
  "# from sentence_transformers import SentenceTransformer\n",
897
  "\n",
 
1353
  "source": [
1354
  "compound_chain = create_retrieval_chain(compound_retriever, document_chain)\n",
1355
  "\n",
1356
+ "# compound_chain.invoke(dict(input = 'Do you know the tragedy of Darth Plagueis the Wise?'))"
1357
  ]
1358
  }
1359
  ],
ingredients.py CHANGED
@@ -29,6 +29,7 @@ from bs4 import BeautifulSoup
29
 
30
  import os
31
  import shutil
 
32
  import re
33
 
34
  import dotenv
@@ -39,46 +40,22 @@ dotenv.load_dotenv()
39
 
40
  ## Vector stores
41
 
42
- script_db = Chroma(embedding_function = SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'), persist_directory = r'scripts\db')
43
- woo_db = Chroma(embedding_function = SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'), persist_directory = r'wookieepedia\db')
44
 
 
 
 
 
45
 
 
 
 
46
 
47
- ## Wookieepedia functions
48
-
49
- def first_wookieepedia_result(query: str) -> str:
50
- '''Get the url of the first result when searching Wookieepedia for a query
51
- (best for simple names as queries, ideally generated by the llm for something like
52
- "Produce a input consisting of the name of the most important element in the query so that its article can be looked up")
53
- '''
54
- search_results = requests.get(f'https://starwars.fandom.com/wiki/Special:Search?query={"+".join(query.split(" "))}')
55
- soup = BeautifulSoup(search_results.content, 'html.parser')
56
- first_res = soup.find('a', class_ = 'unified-search__result__link')
57
- return first_res['href']
58
-
59
-
60
- def get_new_wookieepedia_chunks(query: str, previous_sources: set[str]) -> list[Document]:
61
- '''Retrieve and return chunks of the content of the first result of query on Wookieepedia, then return the closest matches for.
62
- '''
63
- url = first_wookieepedia_result(query)
64
-
65
- if url in previous_sources: return []
66
- else:
67
- doc = WebBaseLoader(url).load()[0] # Only one url passed in => only one Document out; no need to assert
68
-
69
- # There probably is a very long preamble before the real content, however, if more than one gap then ignore and proceed with full document
70
- trimmed = parts[1] if len(parts := doc.page_content.split('\n\n\n\n\n\n\n\n\n\n\n\n\n\n \xa0 \xa0')) == 2 else doc.page_content
71
- doc.page_content = re.sub(r'[\n\t]{2,}', '\n', trimmed) # And remove excessive spacing
72
-
73
- return RecursiveCharacterTextSplitter(chunk_size = 800, chunk_overlap = 100).split_documents([doc])
74
 
75
- def get_wookieepedia_context(original_query: str, simple_query: str, wdb: Chroma) -> list[Document]:
76
- try:
77
- new_chunks = get_new_wookieepedia_chunks(simple_query, previous_sources = set(md.get('source') for md in wdb.get()['metadatas']))
78
- if new_chunks: wdb.add_documents(new_chunks)
79
- except: return []
80
 
81
- return wdb.similarity_search(original_query, k = 10)
 
82
 
83
 
84
 
@@ -105,7 +82,6 @@ document_prompt = ChatPromptTemplate.from_messages([
105
  ])
106
  document_chain = create_stuff_documents_chain(llm, document_prompt)
107
 
108
-
109
  script_retriever_prompt = ChatPromptTemplate.from_messages([
110
  MessagesPlaceholder(variable_name = 'chat_history'),
111
  ('user', '{input}'),
@@ -114,7 +90,6 @@ script_retriever_prompt = ChatPromptTemplate.from_messages([
114
  ])
115
  script_retriever_chain = create_history_aware_retriever(llm, script_db.as_retriever(), script_retriever_prompt) # Essentially just: prompt | llm | StrOutputParser() | retriever
116
 
117
-
118
  woo_retriever_prompt = ChatPromptTemplate.from_messages([
119
  MessagesPlaceholder(variable_name = 'chat_history'),
120
  ('user', '{input}'),
@@ -122,7 +97,6 @@ woo_retriever_prompt = ChatPromptTemplate.from_messages([
122
  ])
123
  woo_retriever_chain = create_history_aware_retriever(llm, woo_db.as_retriever(), woo_retriever_prompt) # Essentially just: prompt | llm | StrOutputParser() | retriever
124
 
125
-
126
  # full_chain = create_retrieval_chain(script_retriever_chain, document_chain)
127
  full_chain = create_retrieval_chain(woo_retriever_chain, document_chain)
128
 
@@ -146,6 +120,7 @@ script_tool = create_retriever_tool(
146
  '''Search the Star Wars film scripts. This tool should be the first choice for Star Wars related questions.
147
  Queries passed to this tool should be lists of keywords likely to be in dialogue or scene descriptions, and should not include film titles.'''
148
  )
 
149
  woo_tool = create_retriever_tool(
150
  woo_db.as_retriever(search_kwargs = dict(k = 4)),
151
  'search_wookieepedia',
@@ -166,6 +141,7 @@ agent_prompt = ChatPromptTemplate.from_messages([
166
  ('placeholder', '{agent_scratchpad}') # Required for chat history and the agent's intermediate processing values
167
  ])
168
  agent = create_tool_calling_agent(llm, tools, agent_prompt)
 
169
  agent_executor = AgentExecutor(agent = agent, tools = tools, verbose = True)
170
 
171
 
@@ -204,3 +180,49 @@ def compound_retriever(question):
204
  compound_chain = create_retrieval_chain(compound_retriever, document_chain)
205
 
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  import os
31
  import shutil
32
+ from pathlib import Path
33
  import re
34
 
35
  import dotenv
 
40
 
41
  ## Vector stores
42
 
43
+ # Non-persistent; build from documents
 
44
 
45
+ # scripts = DirectoryLoader('scripts', glob = '*.txt', loader_cls = TextLoader).load()
46
+ # for s in scripts: s.page_content = re.sub(r'^[\t ]+', '', s.page_content, flags = re.MULTILINE) # Spacing to centre text noise
47
+ # script_chunks = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200, separators = ['\n\n\n', '\n\n', '\n']).split_documents(scripts)
48
+ # script_db = Chroma.from_documents(script_chunks, SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'))
49
 
50
+ # pages = DirectoryLoader('wookieepedia', glob = '*.txt', loader_cls = TextLoader).load()
51
+ # page_chunks = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200, separators = ['\n\n\n', '\n\n', '\n']).split_documents(pages)
52
+ # woo_db = Chroma.from_documents(page_chunks, SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'))
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ # # Load pre-built persistent ones
 
 
 
 
56
 
57
+ script_db = Chroma(embedding_function = SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'), persist_directory = str(Path('scripts') / 'db'))
58
+ woo_db = Chroma(embedding_function = SentenceTransformerEmbeddings(model_name = 'all-MiniLM-L6-v2'), persist_directory = str(Path('wookieepedia') / 'db'))
59
 
60
 
61
 
 
82
  ])
83
  document_chain = create_stuff_documents_chain(llm, document_prompt)
84
 
 
85
  script_retriever_prompt = ChatPromptTemplate.from_messages([
86
  MessagesPlaceholder(variable_name = 'chat_history'),
87
  ('user', '{input}'),
 
90
  ])
91
  script_retriever_chain = create_history_aware_retriever(llm, script_db.as_retriever(), script_retriever_prompt) # Essentially just: prompt | llm | StrOutputParser() | retriever
92
 
 
93
  woo_retriever_prompt = ChatPromptTemplate.from_messages([
94
  MessagesPlaceholder(variable_name = 'chat_history'),
95
  ('user', '{input}'),
 
97
  ])
98
  woo_retriever_chain = create_history_aware_retriever(llm, woo_db.as_retriever(), woo_retriever_prompt) # Essentially just: prompt | llm | StrOutputParser() | retriever
99
 
 
100
  # full_chain = create_retrieval_chain(script_retriever_chain, document_chain)
101
  full_chain = create_retrieval_chain(woo_retriever_chain, document_chain)
102
 
 
120
  '''Search the Star Wars film scripts. This tool should be the first choice for Star Wars related questions.
121
  Queries passed to this tool should be lists of keywords likely to be in dialogue or scene descriptions, and should not include film titles.'''
122
  )
123
+
124
  woo_tool = create_retriever_tool(
125
  woo_db.as_retriever(search_kwargs = dict(k = 4)),
126
  'search_wookieepedia',
 
141
  ('placeholder', '{agent_scratchpad}') # Required for chat history and the agent's intermediate processing values
142
  ])
143
  agent = create_tool_calling_agent(llm, tools, agent_prompt)
144
+
145
  agent_executor = AgentExecutor(agent = agent, tools = tools, verbose = True)
146
 
147
 
 
180
  compound_chain = create_retrieval_chain(compound_retriever, document_chain)
181
 
182
 
183
+
184
+ ## Wookieepedia functions
185
+
186
+ def first_wookieepedia_result(query: str) -> str:
187
+ '''Get the url of the first result when searching Wookieepedia for a query
188
+ (best for simple names as queries, ideally generated by the llm for something like
189
+ "Produce a input consisting of the name of the most important element in the query so that its article can be looked up")
190
+ '''
191
+ search_results = requests.get(f'https://starwars.fandom.com/wiki/Special:Search?query={"+".join(query.split(" "))}')
192
+ soup = BeautifulSoup(search_results.content, 'html.parser')
193
+ first_res = soup.find('a', class_ = 'unified-search__result__link')
194
+ return first_res['href']
195
+
196
+
197
+ def get_wookieepedia_page_content(query: str, previous_sources: set[str]) -> Document | None:
198
+ '''Return cleaned content from a Wookieepedia page provided it was not already sourced
199
+ '''
200
+ url = first_wookieepedia_result(query)
201
+
202
+ if url in previous_sources: return None
203
+ else:
204
+ response = requests.get(url)
205
+ soup = BeautifulSoup(response.content, 'html.parser')
206
+ doc = soup.find('div', id = 'content').get_text()
207
+
208
+ # Cleaning
209
+ doc = doc.split('\n\n\n\n\n\n\n\n\n\n\n\n\n\n')[-1] # The (multiple) preambles are separated by these many newlines; no harm done if not present
210
+ doc = re.sub('\[\d*\]', '', doc) # References (and section title's "[]" suffixes) are noise
211
+ doc = doc.split('\nAppearances\n')[0] # Keep only content before these sections
212
+ doc = doc.split('\nSources\n')[0] # Technically no need to check this if successfully cut on appearances, but no harm done
213
+ doc = re.sub('Contents\n\n(?:[\d\.]+ [^\n]+\n+)+', '', doc) # Remove table of contents
214
+
215
+ return Document(page_content = doc, metadata = dict(source = url))
216
+
217
+ def get_wookieepedia_context(original_query: str, simple_query: str, wdb: Chroma) -> list[Document]:
218
+ try:
219
+ doc = get_wookieepedia_page_content(simple_query, previous_sources = set(md.get('source') for md in wdb.get()['metadatas']))
220
+ if doc is not None:
221
+ new_chunks = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200).split_documents([doc])
222
+ wdb.add_documents(new_chunks)
223
+ print(f"Added new chunks (for '{simple_query}' -> {doc['metadata']['source']}) to the Wookieepedia database.")
224
+ except: return []
225
+
226
+ return wdb.similarity_search(original_query, k = 10)
227
+
228
+
langserve_app.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Chains
2
+ from langchain_core.pydantic_v1 import BaseModel, Field
3
+
4
+ # To serve the app
5
+ from fastapi import FastAPI
6
+ from langchain_core.messages import BaseMessage
7
+ from langserve import add_routes, CustomUserType
8
+
9
+ import dotenv
10
+ dotenv.load_dotenv()
11
+
12
+ from ingredients import script_db, woo_db, full_chain, compound_chain, agent_executor
13
+
14
+
15
+
16
+ ## Type specifications (with unusual class-scope fields)
17
+
18
+ class StrInput(BaseModel):
19
+ input: str
20
+
21
+ class Input(BaseModel):
22
+ input: str
23
+ chat_history: list[BaseMessage] = Field(
24
+ ...,
25
+ extra = dict(widget = dict(type = 'chat', input = 'location')),
26
+ )
27
+
28
+ class Output(BaseModel):
29
+ output: str
30
+
31
+
32
+
33
+ ## App definition
34
+ # NOTE: The chat playground type has a web page issue (flashes and becomes white, hence non-interactable; this was supposedly solved in an issue late last year)
35
+
36
+ app = FastAPI(
37
+ title = 'Star Wars Expert',
38
+ version = '1.0',
39
+ description = 'A Star Wars expert chatbot',
40
+ )
41
+
42
+
43
+ # Basic retriever versions
44
+
45
+ # add_routes(app, script_db.as_retriever())
46
+ # add_routes(app, woo_db.as_retriever())
47
+
48
+
49
+ # History-aware retriever version
50
+ # add_routes(app, full_chain.with_types(input_type = StrInput, output_type = Output), playground_type = 'default')
51
+
52
+
53
+ # Agent version
54
+
55
+ # add_routes(app, agent_executor, playground_type = 'chat')
56
+ # add_routes(app, agent_executor.with_types(input_type = StrInput, output_type = Output))
57
+
58
+
59
+ # Non-agent chain-logic version
60
+
61
+ add_routes(app, compound_chain.with_types(input_type = StrInput))
62
+ # add_routes(app, compound_chain.with_types(input_type = Input), playground_type = 'chat')
63
+
64
+
65
+
66
+ if __name__ == '__main__':
67
+ import uvicorn
68
+
69
+ uvicorn.run(app, host = 'localhost', port = 8000)
70
+
71
+
requirements.txt CHANGED
@@ -1,12 +1,14 @@
1
  beautifulsoup4>=4.12.3
2
- fastapi>=0.110.2
3
  langchain>=0.1.16
4
  langchain_community>=0.0.34
5
  langchain_core>=0.1.45
6
  langchain_openai>=0.1.3
7
- langserve>=0.1.0
8
  sentence-transformers>=2.7.0
9
  python-dotenv>=1.0.1
10
  Requests>=2.31.0
11
- uvicorn>=0.29.0
12
  chromadb>=0.4.24
 
 
 
 
 
 
1
  beautifulsoup4>=4.12.3
 
2
  langchain>=0.1.16
3
  langchain_community>=0.0.34
4
  langchain_core>=0.1.45
5
  langchain_openai>=0.1.3
 
6
  sentence-transformers>=2.7.0
7
  python-dotenv>=1.0.1
8
  Requests>=2.31.0
 
9
  chromadb>=0.4.24
10
+ gradio>=4.27.0
11
+
12
+ # fastapi>=0.110.2
13
+ # langserve>=0.1.0
14
+ # uvicorn>=0.29.0
scripts/db/{ee161592-5f4b-453f-af5c-10f9ed7a57a0 β†’ 9a364cee-0b3d-4004-86d6-7bac58ecc92c}/data_level0.bin RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:698c3f0c09428ffae03ea896c578be3cd69b1b3019d69354e05383663eaf26c3
3
  size 1676000
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b4907f424ad43eafe0706f355d0345cd82ee7798a135f9995233ca7e42bc937d
3
  size 1676000
scripts/db/{ee161592-5f4b-453f-af5c-10f9ed7a57a0 β†’ 9a364cee-0b3d-4004-86d6-7bac58ecc92c}/header.bin RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:29f241a1a6775b5338a81594c5c0ce61c670b325cacc6d674250c7ae3c6b9682
3
  size 100
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bc26d853c2df1dbd2161639e83f53b98808b632c106c529341d0b31f3a0b3e2a
3
  size 100
scripts/db/{ee161592-5f4b-453f-af5c-10f9ed7a57a0 β†’ 9a364cee-0b3d-4004-86d6-7bac58ecc92c}/index_metadata.pickle RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:5e7e2b8a066a226a9961812ad1ef171838def7f221c4f72639b0c1e9ff724e46
3
  size 55974
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7824365e98ba10f9c2112739ddbb7d87839f7c27a662e21ee2fe819677ce0e0e
3
  size 55974
scripts/db/{ee161592-5f4b-453f-af5c-10f9ed7a57a0 β†’ 9a364cee-0b3d-4004-86d6-7bac58ecc92c}/length.bin RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:9e6471f6ab66dac4d5f196ef41fe5461b42784fefbaa4b5c456768ffabbbd3bc
3
  size 4000
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac2283f2e028a485f5564c59ed1722b4e7c01c7dad86578d7572e39b4af15c74
3
  size 4000
scripts/db/{ee161592-5f4b-453f-af5c-10f9ed7a57a0 β†’ 9a364cee-0b3d-4004-86d6-7bac58ecc92c}/link_lists.bin RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:cd75fcf8d5b138005794e3d58997ed37fc05c605f60f77b61399a03a2659333f
3
  size 8624
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f3ace8c9f24593fdd1d5ea5618e39cac109d9663f598c4e0e5ab668534f3b62e
3
  size 8624
scripts/db/chroma.sqlite3 CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:e0cc8b50d0ea411aef4effba6a6cdfad5257875b12e939e334531b534abc5aab
3
- size 12161024
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:08c0800eb8542363f5030d5fa2c1807251c5827bd9a8a1888f923d85cc564951
3
+ size 12173312
testing.ipynb ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Testing of different versions"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "## Local environment"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": null,
20
+ "metadata": {},
21
+ "outputs": [],
22
+ "source": [
23
+ "from ingredients import script_db, woo_db, full_chain, compound_chain, agent_executor"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": null,
29
+ "metadata": {},
30
+ "outputs": [],
31
+ "source": [
32
+ "compound_chain.invoke(dict(input = 'What power source did the Death Star use?', chat_history = []))"
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "markdown",
37
+ "metadata": {},
38
+ "source": [
39
+ "## Gradio app"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": 3,
45
+ "metadata": {},
46
+ "outputs": [
47
+ {
48
+ "name": "stdout",
49
+ "output_type": "stream",
50
+ "text": [
51
+ "Loaded as API: http://127.0.0.1:7860/ βœ”\n"
52
+ ]
53
+ }
54
+ ],
55
+ "source": [
56
+ "from gradio_client import Client\n",
57
+ "\n",
58
+ "# client = Client('T-Flet/Star-Wars-Expert')\n",
59
+ "client = Client('http://127.0.0.1:7860')"
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "code",
64
+ "execution_count": 4,
65
+ "metadata": {},
66
+ "outputs": [
67
+ {
68
+ "data": {
69
+ "text/plain": [
70
+ "'Hello! How can I help you with Star Wars today?'"
71
+ ]
72
+ },
73
+ "execution_count": 4,
74
+ "metadata": {},
75
+ "output_type": "execute_result"
76
+ }
77
+ ],
78
+ "source": [
79
+ "client.predict(message = 'Do you know the tragedy of Darth Plagueis the Wise?', api_name = '/chat')"
80
+ ]
81
+ },
82
+ {
83
+ "cell_type": "markdown",
84
+ "metadata": {},
85
+ "source": [
86
+ "## LangServe app"
87
+ ]
88
+ },
89
+ {
90
+ "cell_type": "code",
91
+ "execution_count": 1,
92
+ "metadata": {},
93
+ "outputs": [],
94
+ "source": [
95
+ "from langserve import RemoteRunnable\n",
96
+ "\n",
97
+ "remote_runnable = RemoteRunnable('http://localhost:8000/')"
98
+ ]
99
+ },
100
+ {
101
+ "cell_type": "code",
102
+ "execution_count": null,
103
+ "metadata": {},
104
+ "outputs": [],
105
+ "source": [
106
+ "# remote_runnable.invoke(dict(input = 'Do you know the tragedy of Darth Plagueis the Wise?', chat_history = []))\n",
107
+ "remote_runnable.invoke(dict(input = 'What power source did the Death Star use?', chat_history = []))"
108
+ ]
109
+ }
110
+ ],
111
+ "metadata": {
112
+ "kernelspec": {
113
+ "display_name": "ML11",
114
+ "language": "python",
115
+ "name": "python3"
116
+ },
117
+ "language_info": {
118
+ "codemirror_mode": {
119
+ "name": "ipython",
120
+ "version": 3
121
+ },
122
+ "file_extension": ".py",
123
+ "mimetype": "text/x-python",
124
+ "name": "python",
125
+ "nbconvert_exporter": "python",
126
+ "pygments_lexer": "ipython3",
127
+ "version": "3.11.7"
128
+ }
129
+ },
130
+ "nbformat": 4,
131
+ "nbformat_minor": 2
132
+ }