ysharma HF staff commited on
Commit
2df0731
·
verified ·
1 Parent(s): af1fda5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +262 -0
app.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import anthropic
3
+ import base64
4
+ from typing import List, Dict, Any
5
+
6
+ # Default document content
7
+ DEFAULT_DOC = "The grass is pink and soil is green. The sky is red while the sun looks blue."
8
+
9
+ def read_pdf_as_base64(file_path: str) -> str:
10
+ """Read a PDF file and return its base64 encoded content."""
11
+ with open(file_path, 'rb') as file:
12
+ return base64.b64encode(file.read()).decode('utf-8')
13
+
14
+ def user_message(
15
+ user_input: str,
16
+ history: list,
17
+ enable_citations: bool,
18
+ doc_type: str,
19
+ text_content: str,
20
+ pdf_file: str,
21
+ api_key: str
22
+ ) -> tuple:
23
+ # logging
24
+ print("\n----------- User Message -------------")
25
+ print(f"User Input: {user_input}")
26
+ print(f"Citations Enabled: {enable_citations}")
27
+ print(f"Document Type: {doc_type}")
28
+
29
+ history.append({
30
+ "role": "user",
31
+ "content": user_input,
32
+ })
33
+ return "", history
34
+
35
+ def format_message_history(
36
+ history: list,
37
+ enable_citations: bool,
38
+ doc_type: str,
39
+ text_content: str,
40
+ pdf_file: str
41
+ ) -> List[Dict]:
42
+ """Convert Gradio chat history to Anthropic message format."""
43
+ formatted_messages = []
44
+
45
+ # Add previous messages
46
+ for msg in history[:-1]:
47
+ if msg["role"] == "user":
48
+ formatted_messages.append({
49
+ "role": "user",
50
+ "content": msg["content"]
51
+ })
52
+ elif msg["role"] == "assistant":
53
+ if "metadata" not in msg or msg["metadata"] is None:
54
+ formatted_messages.append({
55
+ "role": "assistant",
56
+ "content": msg["content"]
57
+ })
58
+
59
+ # Prepare the latest message
60
+ latest_message = {
61
+ "role": "user",
62
+ "content": []
63
+ }
64
+
65
+ # Add document if citations are enabled
66
+ if enable_citations:
67
+ if doc_type == "plain_text":
68
+ latest_message["content"].append({
69
+ "type": "document",
70
+ "source": {
71
+ "type": "text",
72
+ "media_type": "text/plain",
73
+ "data": text_content.strip() if text_content.strip() else DEFAULT_DOC
74
+ },
75
+ "title": "User Document" if text_content.strip() else "Sample Document",
76
+ "citations": {"enabled": True}
77
+ })
78
+ elif doc_type == "pdf" and pdf_file:
79
+ pdf_base64 = read_pdf_as_base64(pdf_file)
80
+ latest_message["content"].append({
81
+ "type": "document",
82
+ "source": {
83
+ "type": "base64",
84
+ "media_type": "application/pdf",
85
+ "data": pdf_base64
86
+ },
87
+ "title": "User PDF Document",
88
+ "citations": {"enabled": True}
89
+ })
90
+
91
+ # Add the user's question
92
+ latest_message["content"].append({
93
+ "type": "text",
94
+ "text": history[-1]["content"]
95
+ })
96
+
97
+ formatted_messages.append(latest_message)
98
+ return formatted_messages
99
+
100
+ def bot_response(
101
+ history: list,
102
+ enable_citations: bool,
103
+ doc_type: str,
104
+ text_content: str,
105
+ pdf_file: str,
106
+ api_key: str
107
+ ) -> List[Dict[str, Any]]:
108
+ try:
109
+ if not api_key:
110
+ history.append({
111
+ "role": "assistant",
112
+ "content": "Please provide your Anthropic API key to continue."
113
+ })
114
+ return history
115
+
116
+ # Initialize client with provided API key
117
+ client = anthropic.Anthropic(api_key=api_key)
118
+
119
+ messages = format_message_history(history, enable_citations, doc_type, text_content, pdf_file)
120
+
121
+ response = client.messages.create(
122
+ model="claude-3-5-sonnet-20241022",
123
+ max_tokens=1024,
124
+ messages=messages
125
+ )
126
+
127
+ # Initialize main response and citations
128
+ main_response = ""
129
+ citations = []
130
+
131
+ # Process each content block
132
+ for block in response.content:
133
+ if block.type == "text":
134
+ main_response += block.text
135
+ if enable_citations and hasattr(block, 'citations') and block.citations:
136
+ for citation in block.citations:
137
+ if citation.cited_text not in citations:
138
+ citations.append(citation.cited_text)
139
+
140
+ # Add main response
141
+ history.append({
142
+ "role": "assistant",
143
+ "content": main_response
144
+ })
145
+
146
+ # Add citations if any were found and citations are enabled
147
+ if enable_citations and citations:
148
+ history.append({
149
+ "role": "assistant",
150
+ "content": "\n".join([f"• {cite}" for cite in citations]),
151
+ "metadata": {"title": "📚 Citations"}
152
+ })
153
+
154
+ return history
155
+
156
+ except Exception as e:
157
+ print(f"Error in bot_response: {str(e)}")
158
+ error_message = str(e)
159
+ if "401" in error_message:
160
+ error_message = "Invalid API key. Please check your Anthropic API key and try again."
161
+ history.append({
162
+ "role": "assistant",
163
+ "content": f"I apologize, but I encountered an error: {error_message}"
164
+ })
165
+ return history
166
+
167
+ def update_document_inputs(enable_citations: bool, doc_type: str = "plain_text"):
168
+ """Update visibility of document input components based on settings."""
169
+ text_visible = enable_citations and doc_type == "plain_text"
170
+ pdf_visible = enable_citations and doc_type == "pdf"
171
+ radio_visible = enable_citations
172
+
173
+ return {
174
+ doc_type_radio: gr.Radio(visible=radio_visible),
175
+ text_input: gr.Textbox(visible=text_visible),
176
+ pdf_input: gr.File(visible=pdf_visible)
177
+ }
178
+
179
+ with gr.Blocks(fill_height=True) as demo:
180
+ gr.Markdown("# Chat with Citations")
181
+
182
+ with gr.Row(scale=1):
183
+ with gr.Column(scale=4):
184
+ chatbot = gr.Chatbot(
185
+ type="messages",
186
+ bubble_full_width=False,
187
+ show_label=False,
188
+ scale=1
189
+ )
190
+
191
+ msg = gr.Textbox(
192
+ placeholder="Enter your message here...",
193
+ show_label=False,
194
+ container=False
195
+ )
196
+
197
+ with gr.Column(scale=1):
198
+ api_key = gr.Textbox(
199
+ type="password",
200
+ label="Anthropic API Key",
201
+ placeholder="Enter your API key",
202
+ info="Your API key will not be stored",
203
+ interactive=True,
204
+ )
205
+
206
+ enable_citations = gr.Checkbox(
207
+ label="Enable Citations",
208
+ value=True,
209
+ info="Toggle citation functionality"
210
+ )
211
+
212
+ doc_type_radio = gr.Radio(
213
+ choices=["plain_text", "pdf"],
214
+ value="plain_text",
215
+ label="Document Type",
216
+ info="Choose the type of document"
217
+ )
218
+
219
+ text_input = gr.Textbox(
220
+ label="Document Content",
221
+ placeholder="Enter your document text here...",
222
+ lines=10,
223
+ info="Enter the text you want to reference. If empty, default document will be used."
224
+ )
225
+
226
+ pdf_input = gr.File(
227
+ label="Upload PDF",
228
+ file_count="single",
229
+ file_types=[".pdf"],
230
+ type="filepath",
231
+ visible=False
232
+ )
233
+
234
+ clear = gr.ClearButton([msg, chatbot, text_input, pdf_input])
235
+
236
+ # Update input visibility based on settings
237
+ enable_citations.change(
238
+ update_document_inputs,
239
+ inputs=[enable_citations, doc_type_radio],
240
+ outputs=[doc_type_radio, text_input, pdf_input]
241
+ )
242
+
243
+ doc_type_radio.change(
244
+ update_document_inputs,
245
+ inputs=[enable_citations, doc_type_radio],
246
+ outputs=[doc_type_radio, text_input, pdf_input]
247
+ )
248
+
249
+ # Handle message submission
250
+ msg.submit(
251
+ user_message,
252
+ [msg, chatbot, enable_citations, doc_type_radio, text_input, pdf_input, api_key],
253
+ [msg, chatbot],
254
+ queue=False
255
+ ).then(
256
+ bot_response,
257
+ [chatbot, enable_citations, doc_type_radio, text_input, pdf_input, api_key],
258
+ chatbot
259
+ )
260
+
261
+ if __name__ == "__main__":
262
+ demo.launch(debug=True)