bluenevus commited on
Commit
d9604c9
·
1 Parent(s): 7eee39f

Update app.py via AI Editor

Browse files
Files changed (1) hide show
  1. app.py +175 -83
app.py CHANGED
@@ -2,14 +2,22 @@ import os
2
  import base64
3
  import io
4
  import dash
5
- from dash import dcc, html, Input, Output, State
6
  import dash_bootstrap_components as dbc
7
  import pandas as pd
8
  import anthropic
9
  from threading import Thread
 
 
 
 
 
 
 
10
 
11
  # Initialize Dash app
12
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
 
13
 
14
  # Anthropic API setup
15
  ANTHROPIC_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
@@ -24,125 +32,209 @@ shredded_document = None
24
  generated_response = None
25
 
26
  # Helper functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def process_document(content, filename, action):
28
  global uploaded_document, shredded_document, generated_response
29
-
30
- content_type, content_string = content.split(',')
31
- decoded = base64.b64decode(content_string)
32
 
33
  if action == 'upload':
34
- uploaded_document = io.StringIO(decoded.decode('utf-8')).read()
 
 
 
 
 
 
 
 
35
  return "Document uploaded successfully."
36
 
37
  elif action == 'shred':
38
- prompt = f"Analyze the following RFP/PWS/SOW/RFI and generate a requirements spreadsheet. Identify requirements by action words like 'shall', 'will', 'perform', etc. Organize by PWS section and requirement. Do not write as if responding to the proposal:\n\n{uploaded_document}"
39
- response = anthropic_client.messages.create(
40
- model=CLAUDE3_SONNET_MODEL,
41
- max_tokens=CLAUDE3_MAX_OUTPUT_TOKENS,
42
- messages=[{"role": "user", "content": prompt}]
 
 
43
  )
44
- shredded_document = response.content[0].text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  return shredded_document
46
 
47
  elif action == 'generate':
48
- prompt = f"Create a highly detailed proposal response based on the following PWS requirements. Be compliant and compelling. Focus on describing the approach, steps, workflow, people, processes, and technology. Refer to research that validates the approach and cite sources with measurable outcomes:\n\n{shredded_document}"
49
- response = anthropic_client.messages.create(
50
- model=CLAUDE3_SONNET_MODEL,
51
- max_tokens=CLAUDE3_MAX_OUTPUT_TOKENS,
52
- messages=[{"role": "user", "content": prompt}]
 
 
53
  )
54
- generated_response = response.content[0].text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  return generated_response
56
 
57
- # Implement other actions (check_compliance, recover_document, virtual_board, estimate_loe) similarly
58
 
59
  # Layout
60
  app.layout = dbc.Container([
61
  dbc.Row([
62
  dbc.Col([
63
- html.H3("Navigation"),
64
- dbc.Button("Shred RFP/PWS/SOW/RFI", id="shred-btn", className="mb-2 w-100"),
65
- dbc.Button("Generate Proposal Response", id="generate-btn", className="mb-2 w-100"),
66
- dbc.Button("Check Compliance", id="compliance-btn", className="mb-2 w-100"),
67
- dbc.Button("Recover Document", id="recover-btn", className="mb-2 w-100"),
68
- dbc.Button("Virtual Board", id="board-btn", className="mb-2 w-100"),
69
- dbc.Button("Estimate LOE", id="loe-btn", className="mb-2 w-100"),
70
- ], width=3),
 
 
 
 
71
  dbc.Col([
72
- dbc.Input(id="chat-input", type="text", placeholder="Enter additional instructions..."),
73
- dbc.Button("Send", id="chat-send-btn", className="mt-2"),
74
- html.Div([
75
- dbc.Button("Shred", id="shred-action-btn", className="mr-2"),
76
- dbc.Button("Generate", id="generate-action-btn", className="mr-2"),
77
- dbc.Button("Check Compliance", id="compliance-action-btn", className="mr-2"),
78
- dbc.Button("Recover", id="recover-action-btn", className="mr-2"),
79
- dbc.Button("Virtual Board", id="board-action-btn", className="mr-2"),
80
- dbc.Button("LOE", id="loe-action-btn"),
81
- ], className="mt-3 mb-3"),
82
- dcc.Upload(
83
- id='upload-document',
84
- children=html.Div([
85
- 'Drag and Drop or ',
86
- html.A('Select Files')
87
- ]),
88
- style={
89
- 'width': '100%',
90
- 'height': '60px',
91
- 'lineHeight': '60px',
92
- 'borderWidth': '1px',
93
- 'borderStyle': 'dashed',
94
- 'borderRadius': '5px',
95
- 'textAlign': 'center',
96
- 'margin': '10px'
97
- },
98
- multiple=False
99
- ),
100
- html.Div(id='output-document-upload'),
101
- dcc.Loading(
102
- id="loading",
103
- type="default",
104
- children=html.Div(id="output-data-upload")
105
- )
 
 
 
 
 
 
 
 
106
  ], width=9)
107
- ])
108
  ], fluid=True)
109
 
110
- # Callbacks
111
  @app.callback(
112
  Output('output-document-upload', 'children'),
113
  Input('upload-document', 'contents'),
114
- State('upload-document', 'filename')
 
115
  )
116
- def update_output(content, filename):
 
117
  if content is not None:
118
  result = process_document(content, filename, 'upload')
119
- return html.Div(result)
 
120
 
 
121
  @app.callback(
122
  Output('output-data-upload', 'children'),
123
- [Input('shred-action-btn', 'n_clicks'),
124
- Input('generate-action-btn', 'n_clicks'),
125
- Input('compliance-action-btn', 'n_clicks'),
126
- Input('recover-action-btn', 'n_clicks'),
127
- Input('board-action-btn', 'n_clicks'),
128
- Input('loe-action-btn', 'n_clicks')],
129
- State('chat-input', 'value')
 
 
 
130
  )
131
- def update_output(shred_clicks, generate_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks, chat_input):
132
- ctx = dash.callback_context
133
  if not ctx.triggered:
 
134
  return "No action taken yet."
135
- else:
136
- button_id = ctx.triggered[0]['prop_id'].split('.')[0]
137
- if button_id == 'shred-action-btn':
138
- return process_document(None, None, 'shred')
139
- elif button_id == 'generate-action-btn':
140
- return process_document(None, None, 'generate')
141
- # Implement other actions similarly
142
-
 
 
 
 
 
 
143
  return "Action not implemented yet."
144
 
145
  if __name__ == '__main__':
146
  print("Starting the Dash application...")
147
- app.run(debug=True, host='0.0.0.0', port=7860)
148
  print("Dash application has finished running.")
 
2
  import base64
3
  import io
4
  import dash
5
+ from dash import dcc, html, Input, Output, State, callback_context
6
  import dash_bootstrap_components as dbc
7
  import pandas as pd
8
  import anthropic
9
  from threading import Thread
10
+ import logging
11
+
12
+ # Logging setup
13
+ logging.basicConfig(
14
+ level=logging.INFO,
15
+ format='[%(asctime)s] %(levelname)s - %(message)s'
16
+ )
17
 
18
  # Initialize Dash app
19
  app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
20
+ server = app.server
21
 
22
  # Anthropic API setup
23
  ANTHROPIC_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
 
32
  generated_response = None
33
 
34
  # Helper functions
35
+ def decode_document(decoded_bytes):
36
+ try:
37
+ # Try UTF-8 first
38
+ content = decoded_bytes.decode('utf-8')
39
+ logging.info("Document decoded as UTF-8.")
40
+ return content
41
+ except UnicodeDecodeError as e_utf8:
42
+ try:
43
+ # Try latin-1 fallback
44
+ content = decoded_bytes.decode('latin-1')
45
+ logging.warning("Document decoded as Latin-1 due to utf-8 decode error: %s", e_utf8)
46
+ return content
47
+ except Exception as e:
48
+ logging.error("Document decode failed for both utf-8 and latin-1: %s", e)
49
+ return None
50
+
51
  def process_document(content, filename, action):
52
  global uploaded_document, shredded_document, generated_response
53
+ logging.info(f"Process document called with action: {action}")
 
 
54
 
55
  if action == 'upload':
56
+ if content is None:
57
+ return "No content uploaded."
58
+ content_type, content_string = content.split(',')
59
+ decoded = base64.b64decode(content_string)
60
+ text = decode_document(decoded)
61
+ if text is None:
62
+ return "Error: Could not decode document. Please upload a valid text file."
63
+ uploaded_document = text
64
+ logging.info("Document uploaded successfully.")
65
  return "Document uploaded successfully."
66
 
67
  elif action == 'shred':
68
+ if not uploaded_document:
69
+ logging.warning("No uploaded document found for shredding.")
70
+ return "No document uploaded."
71
+ prompt = (
72
+ "Analyze the following RFP/PWS/SOW/RFI and generate a requirements spreadsheet. "
73
+ "Identify requirements by action words like 'shall', 'will', 'perform', etc. Organize by PWS section and requirement. "
74
+ "Do not write as if responding to the proposal:\n\n" + uploaded_document
75
  )
76
+ def thread_shred():
77
+ try:
78
+ response = anthropic_client.messages.create(
79
+ model=CLAUDE3_SONNET_MODEL,
80
+ max_tokens=CLAUDE3_MAX_OUTPUT_TOKENS,
81
+ messages=[{"role": "user", "content": prompt}]
82
+ )
83
+ nonlocal shredded_document
84
+ shredded_document = response.content[0].text
85
+ logging.info("Document shredded successfully.")
86
+ except Exception as e:
87
+ shredded_document = f"Error during shredding: {e}"
88
+ logging.error("Error in thread_shred: %s", e)
89
+ shredded_document = "Shredding in progress..."
90
+ t = Thread(target=thread_shred)
91
+ t.start()
92
+ t.join()
93
  return shredded_document
94
 
95
  elif action == 'generate':
96
+ if not shredded_document:
97
+ logging.warning("No shredded document found when generating response.")
98
+ return "Shredded document not available."
99
+ prompt = (
100
+ "Create a highly detailed proposal response based on the following PWS requirements. "
101
+ "Be compliant and compelling. Focus on describing the approach, steps, workflow, people, processes, and technology. "
102
+ "Refer to research that validates the approach and cite sources with measurable outcomes:\n\n" + shredded_document
103
  )
104
+ def thread_generate():
105
+ try:
106
+ response = anthropic_client.messages.create(
107
+ model=CLAUDE3_SONNET_MODEL,
108
+ max_tokens=CLAUDE3_MAX_OUTPUT_TOKENS,
109
+ messages=[{"role": "user", "content": prompt}]
110
+ )
111
+ nonlocal generated_response
112
+ generated_response = response.content[0].text
113
+ logging.info("Proposal response generated successfully.")
114
+ except Exception as e:
115
+ generated_response = f"Error during generation: {e}"
116
+ logging.error("Error in thread_generate: %s", e)
117
+ generated_response = "Generating response..."
118
+ t = Thread(target=thread_generate)
119
+ t.start()
120
+ t.join()
121
  return generated_response
122
 
123
+ return "Action not implemented yet."
124
 
125
  # Layout
126
  app.layout = dbc.Container([
127
  dbc.Row([
128
  dbc.Col([
129
+ dbc.Card([
130
+ dbc.CardHeader(html.H3("Navigation")),
131
+ dbc.CardBody([
132
+ dbc.Button("Shred RFP/PWS/SOW/RFI", id="shred-btn", className="mb-2 w-100 btn-primary"),
133
+ dbc.Button("Generate Proposal Response", id="generate-btn", className="mb-2 w-100 btn-secondary"),
134
+ dbc.Button("Check Compliance", id="compliance-btn", className="mb-2 w-100 btn-tertiary"),
135
+ dbc.Button("Recover Document", id="recover-btn", className="mb-2 w-100 btn-tertiary"),
136
+ dbc.Button("Virtual Board", id="board-btn", className="mb-2 w-100 btn-tertiary"),
137
+ dbc.Button("Estimate LOE", id="loe-btn", className="mb-2 w-100 btn-tertiary"),
138
+ ])
139
+ ])
140
+ ], width=3, style={'minWidth': '260px'}),
141
  dbc.Col([
142
+ dbc.Card([
143
+ dbc.CardHeader(html.H2("RFP Proposal Assistant", style={'wordWrap': 'break-word'})),
144
+ dbc.CardBody([
145
+ dbc.Form([
146
+ dbc.Textarea(id="chat-input", placeholder="Enter additional instructions...", style={"width":"100%", "wordWrap": "break-word"}, className="mb-2"),
147
+ dbc.Button("Send", id="chat-send-btn", className="mt-2 btn-primary")
148
+ ]),
149
+ html.Div([
150
+ dbc.Button("Shred", id="shred-action-btn", className="mr-2 btn-primary"),
151
+ dbc.Button("Generate", id="generate-action-btn", className="mr-2 btn-secondary"),
152
+ dbc.Button("Check Compliance", id="compliance-action-btn", className="mr-2 btn-tertiary"),
153
+ dbc.Button("Recover", id="recover-action-btn", className="mr-2 btn-tertiary"),
154
+ dbc.Button("Virtual Board", id="board-action-btn", className="mr-2 btn-tertiary"),
155
+ dbc.Button("LOE", id="loe-action-btn", className="btn-tertiary"),
156
+ ], className="mt-3 mb-3"),
157
+ dcc.Upload(
158
+ id='upload-document',
159
+ children=html.Div([
160
+ 'Drag and Drop or ',
161
+ html.A('Select Files')
162
+ ]),
163
+ style={
164
+ 'width': '100%',
165
+ 'height': '60px',
166
+ 'lineHeight': '60px',
167
+ 'borderWidth': '1px',
168
+ 'borderStyle': 'dashed',
169
+ 'borderRadius': '5px',
170
+ 'textAlign': 'center',
171
+ 'margin': '10px'
172
+ },
173
+ multiple=False
174
+ ),
175
+ html.Div(id='output-document-upload'),
176
+ dcc.Loading(
177
+ id="loading",
178
+ type="default",
179
+ children=html.Div(id="output-data-upload"),
180
+ style={"textAlign": "center"}
181
+ )
182
+ ])
183
+ ], style={'backgroundColor': 'white'})
184
  ], width=9)
185
+ ], style={'marginTop':'20px'})
186
  ], fluid=True)
187
 
188
+ # Callback for document upload
189
  @app.callback(
190
  Output('output-document-upload', 'children'),
191
  Input('upload-document', 'contents'),
192
+ State('upload-document', 'filename'),
193
+ prevent_initial_call=True
194
  )
195
+ def handle_upload(content, filename):
196
+ logging.info("Upload callback triggered.")
197
  if content is not None:
198
  result = process_document(content, filename, 'upload')
199
+ return html.Div(result, style={"wordWrap": "break-word"})
200
+ return ""
201
 
202
+ # Unified callback for all actions
203
  @app.callback(
204
  Output('output-data-upload', 'children'),
205
+ [
206
+ Input('shred-action-btn', 'n_clicks'),
207
+ Input('generate-action-btn', 'n_clicks'),
208
+ Input('compliance-action-btn', 'n_clicks'),
209
+ Input('recover-action-btn', 'n_clicks'),
210
+ Input('board-action-btn', 'n_clicks'),
211
+ Input('loe-action-btn', 'n_clicks')
212
+ ],
213
+ State('chat-input', 'value'),
214
+ prevent_initial_call=True
215
  )
216
+ def handle_actions(shred_clicks, generate_clicks, compliance_clicks, recover_clicks, board_clicks, loe_clicks, chat_input):
217
+ ctx = callback_context
218
  if not ctx.triggered:
219
+ logging.info("No action triggered yet.")
220
  return "No action taken yet."
221
+ button_id = ctx.triggered[0]['prop_id'].split('.')[0]
222
+ logging.info(f"Button pressed: {button_id}")
223
+ if button_id == 'shred-action-btn':
224
+ return process_document(None, None, 'shred')
225
+ elif button_id == 'generate-action-btn':
226
+ return process_document(None, None, 'generate')
227
+ elif button_id == 'compliance-action-btn':
228
+ return "Compliance checking not implemented yet."
229
+ elif button_id == 'recover-action-btn':
230
+ return "Recovery not implemented yet."
231
+ elif button_id == 'board-action-btn':
232
+ return "Virtual board not implemented yet."
233
+ elif button_id == 'loe-action-btn':
234
+ return "LOE estimation not implemented yet."
235
  return "Action not implemented yet."
236
 
237
  if __name__ == '__main__':
238
  print("Starting the Dash application...")
239
+ app.run(debug=True, host='0.0.0.0', port=7860, threaded=True)
240
  print("Dash application has finished running.")