SauravMaheshkar commited on
Commit
99edc15
Β·
unverified Β·
1 Parent(s): 9f2858d

feat: init

Browse files
Files changed (2) hide show
  1. app.py +197 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from typing import Dict, List, Optional, TypeAlias
3
+
4
+ import gradio as gr
5
+ import torch
6
+ import weave
7
+ from papersai.utils import load_paper_as_context
8
+ from transformers import AutoTokenizer, pipeline
9
+
10
+ HistoryType: TypeAlias = List[Dict[str, str]]
11
+
12
+ # Initialize the LLM and Weave client
13
+ client = weave.init("papersai")
14
+ checkpoint: str = "HuggingFaceTB/SmolLM2-135M-Instruct"
15
+ tokenizer = AutoTokenizer.from_pretrained(checkpoint)
16
+ pipe = pipeline(
17
+ model=checkpoint,
18
+ torch_dtype=torch.bfloat16,
19
+ device_map="auto",
20
+ )
21
+
22
+
23
+ class ChatState:
24
+ """Utility class to store context and last response"""
25
+
26
+ def __init__(self):
27
+ self.context = None
28
+ self.last_response = None
29
+
30
+
31
+ def record_feedback(x: gr.LikeData) -> None:
32
+ """
33
+ Logs user feedback on the assistant's response in the form of a
34
+ like/dislike reaction.
35
+
36
+ Reference:
37
+ * https://weave-docs.wandb.ai/guides/tracking/feedback
38
+
39
+ Args:
40
+ x (gr.LikeData): User feedback data
41
+
42
+ Returns:
43
+ None
44
+ """
45
+ call = state.last_response
46
+
47
+ # Remove any existing feedback before adding new feedback
48
+ for existing_feedback in list(call.feedback):
49
+ call.feedback.purge(existing_feedback.id)
50
+
51
+ if x.liked:
52
+ call.feedback.add_reaction("πŸ‘")
53
+ else:
54
+ call.feedback.add_reaction("πŸ‘Ž")
55
+
56
+
57
+ @weave.op()
58
+ def invoke(history: HistoryType):
59
+ """
60
+ Simple wrapper around llm inference wrapped in a weave op
61
+
62
+ Args:
63
+ history (HistoryType): Chat history
64
+
65
+ Returns:
66
+ BaseMessage: Response from the model
67
+ """
68
+ input_text = tokenizer.apply_chat_template(history, tokenize=False)
69
+ response = pipe(input_text, do_sample=True, top_p=0.95, max_new_tokens=1024)[0][
70
+ "generated_text"
71
+ ]
72
+ return response
73
+
74
+
75
+ def update_state(history: HistoryType, message: Optional[Dict[str, str]]):
76
+ """
77
+ Update history and app state with the latest user input.
78
+
79
+ Args:
80
+ history (HistoryType): Chat history
81
+ message (Optional[Dict[str, str]]): User input message
82
+
83
+ Returns:
84
+ Tuple[HistoryType, gr.MultimodalTextbox]: Updated history and chat input
85
+ """
86
+ if message is None:
87
+ return history, gr.MultimodalTextbox(value=None, interactive=True)
88
+
89
+ # Initialize history if None
90
+ if history is None:
91
+ history = []
92
+
93
+ # Handle file uploads without adding to visible history
94
+ if isinstance(message, dict) and "files" in message:
95
+ for file_path in message["files"]:
96
+ try:
97
+ state.context = load_paper_as_context(file_path=file_path)
98
+ doc_context = [x.get_content() for x in state.context]
99
+ history.append({"role": "assistant", "content": " ".join(doc_context)})
100
+ except Exception as e:
101
+ history.append(
102
+ {"role": "assistant", "content": f"Error loading file: {str(e)}"}
103
+ )
104
+
105
+ # Handle text input
106
+ if isinstance(message, dict) and message.get("text"):
107
+ history.append({"role": "user", "content": message["text"]})
108
+
109
+ return history, gr.MultimodalTextbox(value=None, interactive=True)
110
+
111
+
112
+ def bot(history: HistoryType):
113
+ """
114
+ Generate response from the LLM and stream it back to the user.
115
+
116
+ Args:
117
+ history (HistoryType): Chat history
118
+
119
+ Yields:
120
+ response from the LLM
121
+ """
122
+ if not history:
123
+ return history
124
+
125
+ try:
126
+ # Get response from LLM
127
+ response, call = invoke.call(history)
128
+ state.last_response = call
129
+
130
+ # Add empty assistant message
131
+ history.append({"role": "assistant", "content": ""})
132
+
133
+ # Stream the response
134
+ for character in response:
135
+ history[-1]["content"] += character
136
+ time.sleep(0.02)
137
+ yield history
138
+
139
+ except Exception as e:
140
+ history.append({"role": "assistant", "content": f"Error: {str(e)}"})
141
+ yield history
142
+
143
+
144
+ def create_interface():
145
+ with gr.Blocks() as demo:
146
+ with weave.attributes({"session": "hf-app"}):
147
+ global state
148
+ state = ChatState()
149
+ gr.Markdown(
150
+ """
151
+ <a href="https://github.com/SauravMaheshkar/papersai">
152
+ <div align="center"><h1>papers.ai</h1></div>
153
+ </a>
154
+ """,
155
+ )
156
+ chatbot = gr.Chatbot(
157
+ show_label=False,
158
+ height=600,
159
+ type="messages",
160
+ show_copy_all_button=True,
161
+ placeholder="Upload a research paper and ask questions!!",
162
+ )
163
+
164
+ chat_input = gr.MultimodalTextbox(
165
+ interactive=True,
166
+ file_count="single",
167
+ placeholder="Upload a document or type your message...",
168
+ show_label=False,
169
+ )
170
+
171
+ chat_msg = chat_input.submit(
172
+ fn=update_state,
173
+ inputs=[chatbot, chat_input],
174
+ outputs=[chatbot, chat_input],
175
+ )
176
+
177
+ bot_msg = chat_msg.then( # noqa: F841
178
+ fn=bot, inputs=[chatbot], outputs=chatbot, api_name="bot_response"
179
+ )
180
+
181
+ chatbot.like(
182
+ fn=record_feedback,
183
+ inputs=None,
184
+ outputs=None,
185
+ like_user_message=True,
186
+ )
187
+
188
+ return demo
189
+
190
+
191
+ def main():
192
+ demo = create_interface()
193
+ demo.launch(share=False)
194
+
195
+
196
+ if __name__ == "__main__":
197
+ main()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ git+https://github.com/SauravMaheshkar/papersai.git
2
+ weave