SimaFarazi commited on
Commit
2fa9347
β€’
1 Parent(s): feb1823

finalize simple stream app

Browse files
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .*
2
+ !/.gitignore
app_simple_stream/app/__pycache__/chains.cpython-312.pyc ADDED
Binary file (935 Bytes). View file
 
app_simple_stream/app/__pycache__/prompts.cpython-312.pyc ADDED
Binary file (377 Bytes). View file
 
app_simple_stream/app/__pycache__/schemas.cpython-312.pyc ADDED
Binary file (490 Bytes). View file
 
app_simple_stream/app/{testing.ipynb β†’ test_components.ipynb} RENAMED
@@ -73,6 +73,83 @@
73
  "user_question"
74
  ]
75
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  {
77
  "cell_type": "code",
78
  "execution_count": null,
 
73
  "user_question"
74
  ]
75
  },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": 1,
79
+ "metadata": {},
80
+ "outputs": [
81
+ {
82
+ "name": "stderr",
83
+ "output_type": "stream",
84
+ "text": [
85
+ "/Users/sima/opt/anaconda3/envs/llm_app_rag/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
86
+ " from .autonotebook import tqdm as notebook_tqdm\n"
87
+ ]
88
+ },
89
+ {
90
+ "name": "stdout",
91
+ "output_type": "stream",
92
+ "text": [
93
+ "The token has not been saved to the git credentials helper. Pass `add_to_git_credential=True` in this function directly or `--add-to-git-credential` if using via `huggingface-cli` if you want to set the git credential as well.\n",
94
+ "Token is valid (permission: write).\n",
95
+ "Your token has been saved to /Users/sima/.cache/huggingface/token\n",
96
+ "Login successful\n"
97
+ ]
98
+ },
99
+ {
100
+ "name": "stderr",
101
+ "output_type": "stream",
102
+ "text": [
103
+ "/Users/sima/opt/anaconda3/envs/llm_app_rag/lib/python3.12/site-packages/huggingface_hub/inference/_client.py:2027: FutureWarning: `stop_sequences` is a deprecated argument for `text_generation` task and will be removed in version '0.28.0'. Use `stop` instead.\n",
104
+ " warnings.warn(\n"
105
+ ]
106
+ },
107
+ {
108
+ "name": "stdout",
109
+ "output_type": "stream",
110
+ "text": [
111
+ " I hope you're doing well. I'm so excited to be writing to you today. I just wanted to say thank you for everything you do. I know it can't be easy, but you make it look effortless.\n",
112
+ "I was thinking about your job the other day, and I realized just how much you do. You're not just a [job title], you're a problem solver, a mediator, a leader, and so much more. You make a difference in people's lives every day, and that's truly amazing.\n",
113
+ "\n",
114
+ "I know that sometimes it can be tough, and you might feel like you're just going through the motions. But I want you to know that you're not. You're making a real impact, and it's not going unnoticed.\n",
115
+ "\n",
116
+ "I hope you know that you're appreciated, and that you're valued. You're an important part of [organization/team/community], and we're all better because of you.\n",
117
+ "\n",
118
+ "Thank you again for all that you do. I'm so grateful to have you in my life, and I hope you know that you're making a difference.\n",
119
+ "\n",
120
+ "Sincerely,\n",
121
+ "[Your Name] How are you? I hope you're doing well. I'm so excited to be writing to you today. I just wanted to say thank you for everything you do. I know it can't be easy, but you make it look effortless.\n",
122
+ "\n",
123
+ "I was thinking about your job the other day, and I realized just how much you do. You're not just a [job title], you're a problem solver, a mediator, a leader, and so much more. You make a difference in people's lives every day, and that's truly amazing.\n",
124
+ "\n",
125
+ "I know that sometimes it can be tough, and you might feel like you're just going through the motions. But I want you to know that you're not. You're making a real impact, and it's not going unnoticed.\n",
126
+ "\n",
127
+ "I hope you know that you're appreciated, and that you're valued. You're an important part of [organization/team/community], and we're all better because of you.\n",
128
+ "\n",
129
+ "Thank you again for all that you do. I'm so grateful to have you in my life, and I hope you know that you're making a difference.\n",
130
+ "\n",
131
+ "Sincerely,\n",
132
+ "[Your Name]\n",
133
+ "How are you? I hope you're doing well. I'm so excited to be writing to you today. I just wanted to say thank you for everything you do. I know it can't be easy, but you make it look effortless.\n",
134
+ "\n",
135
+ "I was thinking"
136
+ ]
137
+ }
138
+ ],
139
+ "source": [
140
+ "# To ensure os.environ['HF_TOKEN'] works use dotenv\n",
141
+ "import os\n",
142
+ "from dotenv import load_dotenv\n",
143
+ "load_dotenv()\n",
144
+ "\n",
145
+ "from chains import simple_chain\n",
146
+ "stream = simple_chain.stream(input={'question':'How are you?'})\n",
147
+ "for chunk in stream: # Each chunk corresponds to a token/word\n",
148
+ " #end=\"\": prints worlds one after each other, an not in a separate lines\n",
149
+ " #flush=True: prints world to the screen immidiately without any buffer\n",
150
+ " print(chunk, end=\"\", flush=True) "
151
+ ]
152
+ },
153
  {
154
  "cell_type": "code",
155
  "execution_count": null,
app_simple_stream/app_backup/callbacks.py DELETED
@@ -1,24 +0,0 @@
1
- from typing import Dict, Any, List
2
- from langchain_core.callbacks import BaseCallbackHandler
3
- import schemas
4
- import crud
5
-
6
-
7
- class LogResponseCallback(BaseCallbackHandler):
8
-
9
- def __init__(self, user_request: schemas.UserRequest, db):
10
- super().__init__()
11
- self.user_request = user_request
12
- self.db = db
13
-
14
- def on_llm_end(self, outputs: Dict[str, Any], **kwargs: Any) -> Any:
15
- """Run when llm ends running."""
16
- # TODO: The function on_llm_end is going to be called when the LLM stops sending
17
- # the response. Use the crud.add_message function to capture that response.
18
- raise NotImplemented
19
-
20
- def on_llm_start(
21
- self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
22
- ) -> Any:
23
- for prompt in prompts:
24
- print(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/chains.py DELETED
@@ -1,55 +0,0 @@
1
- import os
2
- from langchain_huggingface import HuggingFaceEndpoint
3
- from langchain_core.runnables import RunnablePassthrough
4
- import schemas
5
- from prompts import (
6
- raw_prompt,
7
- #format_context,
8
- #tokenizer
9
- )
10
- #from data_indexing import DataIndexer
11
- from transformers import AutoTokenizer
12
-
13
- #data_indexer = DataIndexer()
14
-
15
- model_id = "meta-llama/Meta-Llama-3-8B-Instruct"
16
- tokenizer = AutoTokenizer.from_pretrained(model_id)
17
- llm = HuggingFaceEndpoint(
18
- repo_id="meta-llama/Meta-Llama-3-8B-Instruct",
19
- huggingfacehub_api_token=os.environ['HF_TOKEN'],
20
- max_new_tokens=512,
21
- stop_sequences=[tokenizer.eos_token],
22
- streaming=True,
23
- )
24
-
25
- simple_chain = (raw_prompt | llm).with_types(input_type=schemas.UserQuestion)
26
-
27
- # TODO: create formatted_chain by piping raw_prompt_formatted and the LLM endpoint.
28
- formatted_chain = None
29
-
30
- # TODO: use history_prompt_formatted and HistoryInput to create the history_chain
31
- history_chain = None
32
-
33
- # TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
34
- standalone_chain = None
35
-
36
- # input_1 = RunnablePassthrough.assign(new_question=standalone_chain)
37
- # input_2 = {
38
- # 'context': lambda x: format_context(data_indexer.search(x['new_question'])),
39
- # 'standalone_question': lambda x: x['new_question']
40
- # }
41
- # input_to_rag_chain = input_1 | input_2
42
-
43
- # TODO: use input_to_rag_chain, rag_prompt_formatted,
44
- # HistoryInput and the LLM to build the rag_chain.
45
- rag_chain = None
46
-
47
- # TODO: Implement the filtered_rag_chain. It should be the
48
- # same as the rag_chain but with hybrid_search = True.
49
- filtered_rag_chain = None
50
-
51
-
52
-
53
-
54
-
55
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/crud.py DELETED
@@ -1,23 +0,0 @@
1
- from sqlalchemy.orm import Session
2
- import models, schemas
3
-
4
-
5
- def get_or_create_user(db: Session, username: str):
6
- user = db.query(models.User).filter(models.User.username == username).first()
7
- if not user:
8
- user = models.User(username=username)
9
- db.add(user)
10
- db.commit()
11
- db.refresh(user)
12
- return user
13
-
14
- def add_message(db: Session, message: schemas.MessageBase, username: str):
15
- # TODO: Implement the add_message function. It should:
16
- # - get or create the user with the username
17
- # - create a models.Message instance
18
- # - pass the retrieved user to the message instance
19
- # - save the message instance to the database
20
- raise NotImplemented
21
-
22
- def get_user_chat_history(db: Session, username: str):
23
- raise NotImplemented
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/data_indexing.py DELETED
@@ -1,150 +0,0 @@
1
- import os
2
- import uuid
3
- from pathlib import Path
4
- from pinecone.grpc import PineconeGRPC as Pinecone
5
- from pinecone import ServerlessSpec
6
- from langchain_community.vectorstores import Chroma
7
- from langchain_openai import OpenAIEmbeddings
8
-
9
- current_dir = Path(__file__).resolve().parent
10
-
11
-
12
- class DataIndexer:
13
-
14
- source_file = os.path.join(current_dir, 'sources.txt')
15
-
16
- def __init__(self, index_name='langchain-repo') -> None:
17
-
18
- # TODO: choose your embedding model
19
- # self.embedding_client = InferenceClient(
20
- # "dunzhang/stella_en_1.5B_v5",
21
- # token=os.environ['HF_TOKEN'],
22
- # )
23
- self.embedding_client = OpenAIEmbeddings()
24
- self.index_name = index_name
25
- self.pinecone_client = Pinecone(api_key=os.environ.get('PINECONE_API_KEY'))
26
-
27
- if index_name not in self.pinecone_client.list_indexes().names():
28
- # TODO: create your index if it doesn't exist. Use the create_index function.
29
- # Make sure to choose the dimension that corresponds to your embedding model
30
- pass
31
-
32
- self.index = self.pinecone_client.Index(self.index_name)
33
- # TODO: make sure to build the index.
34
- self.source_index = None
35
-
36
- def get_source_index(self):
37
- if not os.path.isfile(self.source_file):
38
- print('No source file')
39
- return None
40
-
41
- print('create source index')
42
-
43
- with open(self.source_file, 'r') as file:
44
- sources = file.readlines()
45
-
46
- sources = [s.rstrip('\n') for s in sources]
47
- vectorstore = Chroma.from_texts(
48
- sources, embedding=self.embedding_client
49
- )
50
- return vectorstore
51
-
52
- def index_data(self, docs, batch_size=32):
53
-
54
- with open(self.source_file, 'a') as file:
55
- for doc in docs:
56
- file.writelines(doc.metadata['source'] + '\n')
57
-
58
- for i in range(0, len(docs), batch_size):
59
- batch = docs[i: i + batch_size]
60
-
61
- # TODO: create a list of the vector representations of each text data in the batch
62
- # TODO: choose your embedding model
63
- # values = self.embedding_client.embed_documents([
64
- # doc.page_content for doc in batch
65
- # ])
66
-
67
- # values = self.embedding_client.feature_extraction([
68
- # doc.page_content for doc in batch
69
- # ])
70
- values = None
71
-
72
- # TODO: create a list of unique identifiers for each element in the batch with the uuid package.
73
- vector_ids = None
74
-
75
- # TODO: create a list of dictionaries representing the metadata. Capture the text data
76
- # with the "text" key, and make sure to capture the rest of the doc.metadata.
77
- metadatas = None
78
-
79
- # create a list of dictionaries with keys "id" (the unique identifiers), "values"
80
- # (the vector representation), and "metadata" (the metadata).
81
- vectors = [{
82
- 'id': vector_id,
83
- 'values': value,
84
- 'metadata': metadata
85
- } for vector_id, value, metadata in zip(vector_ids, values, metadatas)]
86
-
87
- try:
88
- # TODO: Use the function upsert to upload the data to the database.
89
- upsert_response = None
90
- print(upsert_response)
91
- except Exception as e:
92
- print(e)
93
-
94
- def search(self, text_query, top_k=5, hybrid_search=False):
95
-
96
- filter = None
97
- if hybrid_search and self.source_index:
98
- # I implemented the filtering process to pull the 50 most relevant file names
99
- # to the question. Make sure to adjust this number as you see fit.
100
- source_docs = self.source_index.similarity_search(text_query, 50)
101
- filter = {"source": {"$in":[doc.page_content for doc in source_docs]}}
102
-
103
- # TODO: embed the text_query by using the embedding model
104
- # TODO: choose your embedding model
105
- # vector = self.embedding_client.feature_extraction(text_query)
106
- # vector = self.embedding_client.embed_query(text_query)
107
- vector = None
108
-
109
- # TODO: use the vector representation of the text_query to
110
- # search the database by using the query function.
111
- result = None
112
-
113
- docs = []
114
- for res in result["matches"]:
115
- # TODO: From the result's metadata, extract the "text" element.
116
- pass
117
-
118
- return docs
119
-
120
-
121
- if __name__ == '__main__':
122
-
123
- from langchain_community.document_loaders import GitLoader
124
- from langchain_text_splitters import (
125
- Language,
126
- RecursiveCharacterTextSplitter,
127
- )
128
-
129
- loader = GitLoader(
130
- clone_url="https://github.com/langchain-ai/langchain",
131
- repo_path="./code_data/langchain_repo/",
132
- branch="master",
133
- )
134
-
135
- python_splitter = RecursiveCharacterTextSplitter.from_language(
136
- language=Language.PYTHON, chunk_size=10000, chunk_overlap=100
137
- )
138
-
139
- docs = loader.load()
140
- docs = [doc for doc in docs if doc.metadata['file_type'] in ['.py', '.md']]
141
- docs = [doc for doc in docs if len(doc.page_content) < 50000]
142
- docs = python_splitter.split_documents(docs)
143
- for doc in docs:
144
- doc.page_content = '# {}\n\n'.format(doc.metadata['source']) + doc.page_content
145
-
146
- indexer = DataIndexer()
147
- with open('/app/sources.txt', 'a') as file:
148
- for doc in docs:
149
- file.writelines(doc.metadata['source'] + '\n')
150
- indexer.index_data(docs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/main.py DELETED
@@ -1,87 +0,0 @@
1
- from langchain_core.runnables import Runnable
2
- from langchain_core.callbacks import BaseCallbackHandler
3
- from fastapi import FastAPI, Request, Depends
4
- from sse_starlette.sse import EventSourceResponse
5
- from langserve.serialization import WellKnownLCSerializer
6
- from typing import List
7
- from sqlalchemy.orm import Session
8
-
9
- import schemas
10
- from chains import simple_chain
11
- #import crud, models, schemas
12
- from database import SessionLocal, engine
13
- #from callbacks import LogResponseCallback
14
-
15
-
16
- #models.Base.metadata.create_all(bind=engine)
17
-
18
- app = FastAPI()
19
-
20
- def get_db():
21
- db = SessionLocal()
22
- try:
23
- yield db
24
- finally:
25
- db.close()
26
-
27
-
28
- async def generate_stream(input_data: schemas.BaseModel, runnable: Runnable, callbacks: List[BaseCallbackHandler]=[]):
29
- for output in runnable.stream(input_data.dict(), config={"callbacks": callbacks}):
30
- data = WellKnownLCSerializer().dumps(output).decode("utf-8")
31
- yield {'data': data, "event": "data"}
32
- yield {"event": "end"}
33
-
34
-
35
- @app.post("/simple/stream")
36
- async def simple_stream(request: Request):
37
- data = await request.json()
38
- user_question = schemas.UserQuestion(**data['input'])
39
- return EventSourceResponse(generate_stream(user_question, simple_chain))
40
-
41
-
42
- @app.post("/formatted/stream")
43
- async def formatted_stream(request: Request):
44
- # TODO: use the formatted_chain to implement the "/formatted/stream" endpoint.
45
- raise NotImplemented
46
-
47
-
48
- @app.post("/history/stream")
49
- async def history_stream(request: Request, db: Session = Depends(get_db)):
50
- # TODO: Let's implement the "/history/stream" endpoint. The endpoint should follow those steps:
51
- # - The endpoint receives the request
52
- # - The request is parsed into a user request
53
- # - The user request is used to pull the chat history of the user
54
- # - We add as part of the user history the current question by using add_message.
55
- # - We create an instance of HistoryInput by using format_chat_history.
56
- # - We use the history input within the history chain.
57
- raise NotImplemented
58
-
59
-
60
- @app.post("/rag/stream")
61
- async def rag_stream(request: Request, db: Session = Depends(get_db)):
62
- # TODO: Let's implement the "/rag/stream" endpoint. The endpoint should follow those steps:
63
- # - The endpoint receives the request
64
- # - The request is parsed into a user request
65
- # - The user request is used to pull the chat history of the user
66
- # - We add as part of the user history the current question by using add_message.
67
- # - We create an instance of HistoryInput by using format_chat_history.
68
- # - We use the history input within the rag chain.
69
- raise NotImplemented
70
-
71
-
72
- @app.post("/filtered_rag/stream")
73
- async def filtered_rag_stream(request: Request, db: Session = Depends(get_db)):
74
- # TODO: Let's implement the "/filtered_rag/stream" endpoint. The endpoint should follow those steps:
75
- # - The endpoint receives the request
76
- # - The request is parsed into a user request
77
- # - The user request is used to pull the chat history of the user
78
- # - We add as part of the user history the current question by using add_message.
79
- # - We create an instance of HistoryInput by using format_chat_history.
80
- # - We use the history input within the filtered rag chain.
81
- raise NotImplemented
82
-
83
-
84
-
85
- if __name__ == "__main__":
86
- import uvicorn
87
- uvicorn.run("main:app", host="localhost", reload=True, port=8000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/models.py DELETED
@@ -1,21 +0,0 @@
1
- from sqlalchemy import Column, ForeignKey, Integer, String, DateTime
2
- from sqlalchemy.orm import relationship
3
-
4
- from database import Base
5
-
6
- class User(Base):
7
- __tablename__ = "users"
8
-
9
- id = Column(Integer, primary_key=True, index=True)
10
- username = Column(String, unique=True, index=True)
11
- messages = relationship("Message", back_populates="user")
12
-
13
- # TODO: Implement the Message SQLAlchemy model. Message should have a primary key,
14
- # a message attribute to store the content of messages, a type, AI or Human,
15
- # depending on if it is a user question or an AI response, a timestamp to
16
- # order by time and a user attribute to get the user instance associated
17
- # with the message. We also need a user_id that will use the User.id
18
- # attribute as a foreign key.
19
- class Message(Base):
20
- __tablename__ = "messages"
21
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/app_backup/schemas.py DELETED
@@ -1,21 +0,0 @@
1
-
2
- #from pydantic.v1 import BaseModel
3
- from langserve._pydantic import BaseModel
4
-
5
-
6
- class UserQuestion(BaseModel):
7
- question: str
8
-
9
- # TODO: create a HistoryInput data model with a chat_history and question attributes.
10
- class HistoryInput(BaseModel):
11
- pass
12
-
13
- # TODO: let's create a UserRequest data model with a question and username attribute.
14
- # This will be used to parse the input request.
15
- class UserRequest(BaseModel):
16
- username: str
17
-
18
- # TODO: implement MessageBase as a schema mapping from the database model to the
19
- # FastAPI data model. Basically MessageBase should have the same attributes as models.Message
20
- class MessageBase(BaseModel):
21
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple_stream/test.py CHANGED
@@ -1,5 +1,6 @@
1
  from langserve import RemoteRunnable
2
  # Hit our enpoint with specified rout
 
3
  url = "https://simafarazi-backend-c.hf.space/simple/"
4
  chain = RemoteRunnable(url) #Client for iteracting with LangChain runnables that are hosted as LangServe endpoints
5
  stream = chain.stream(input={'question':'How are you?'}) # .stream() and .invoke() are standard methods to interact with hosted runnables
 
1
  from langserve import RemoteRunnable
2
  # Hit our enpoint with specified rout
3
+ # If we put /simple/stream, it complains; because chain.stream will hit /simple/stream endpoint
4
  url = "https://simafarazi-backend-c.hf.space/simple/"
5
  chain = RemoteRunnable(url) #Client for iteracting with LangChain runnables that are hosted as LangServe endpoints
6
  stream = chain.stream(input={'question':'How are you?'}) # .stream() and .invoke() are standard methods to interact with hosted runnables