rishisriv-bh commited on
Commit
b12a659
Β·
verified Β·
1 Parent(s): 9c97640

Update app_chatgpt.py

Browse files
Files changed (1) hide show
  1. app_chatgpt.py +170 -57
app_chatgpt.py CHANGED
@@ -4,85 +4,172 @@ import os
4
  import gradio as gr
5
  import boto3
6
  import uuid
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- # βœ… Load your secrets from environment
9
- openai.api_key = os.environ.get("Open_ai_key")
10
- bucket_name = os.environ.get("Bucket_name")
11
 
12
- session = boto3.Session(
13
- aws_access_key_id=os.getenv("access_key"),
14
- aws_secret_access_key=os.getenv("secret_access_key")
15
- )
16
 
17
- def upload_files_to_s3(erp_file_path, external_file_path, content, bucket_name):
18
- s3 = session.client("s3")
19
- session_id = str(uuid.uuid4())
20
 
21
- base_erp = os.path.splitext(os.path.basename(erp_file_path))[0]
22
- base_bank = os.path.splitext(os.path.basename(external_file_path))[0]
 
23
 
24
- # Add session ID to filenames
25
- erp_filename = f"{base_erp}_{session_id}.csv"
26
- bank_filename = f"{base_bank}_{session_id}.csv"
27
- txt_filename = f"{session_id}.txt"
28
 
29
- # Write reconciliation output to local file
30
- with open(txt_filename, "w", encoding="utf-8") as file:
31
- file.write(content)
 
32
 
33
- # === Separate folders by type ===
34
- erp_s3_key = f"ERP Statements/{erp_filename}"
35
- bank_s3_key = f"Bank Statements/{bank_filename}"
36
- txt_s3_key = f"Reconciliation Results/{txt_filename}"
37
 
38
- # === Combined folder for each run ===
39
- combined_prefix = f"Combined Files/{session_id}/"
40
- erp_combined_key = combined_prefix + erp_filename
41
- bank_combined_key = combined_prefix + bank_filename
42
- txt_combined_key = combined_prefix + txt_filename
 
 
 
43
 
44
- # βœ… Upload to type-based folders
45
- s3.upload_file(erp_file_path, bucket_name, erp_s3_key)
46
- s3.upload_file(external_file_path, bucket_name, bank_s3_key)
47
- s3.upload_file(txt_filename, bucket_name, txt_s3_key)
48
 
49
- # βœ… Upload to combined folder
50
- s3.upload_file(erp_file_path, bucket_name, erp_combined_key)
51
- s3.upload_file(external_file_path, bucket_name, bank_combined_key)
52
- s3.upload_file(txt_filename, bucket_name, txt_combined_key)
53
 
54
- os.remove(txt_filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- return {
57
- "erp_s3_key": erp_s3_key,
58
- "bank_s3_key": bank_s3_key,
59
- "result_s3_key": txt_s3_key,
60
- "combined_keys": [erp_combined_key, bank_combined_key, txt_combined_key],
61
- "session_id": session_id
62
- }
63
 
64
 
65
  # βœ… Extract transactions from CSV only
66
  def extract_transactions(file):
 
 
67
  filename = file.name.lower()
68
  if not filename.endswith(".csv"):
69
- raise ValueError(
70
- f"Unsupported file format: {filename}. Please upload a CSV file only."
71
- )
72
 
73
  try:
74
  df = pd.read_csv(file.name)
 
 
 
 
75
  return df.to_string(index=False)
76
  except Exception as e:
77
- raise ValueError(f"Error processing {file.name}: {e}")
 
 
78
 
79
 
80
  # βœ… Reconcile the statements using OpenAI
81
  def reconcile_statements_openai(erp_file, external_file):
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  yield "⏳ Processing your request...", ""
83
 
84
  try:
 
 
85
  erp_data = extract_transactions(erp_file)
 
 
86
  external_data = extract_transactions(external_file)
87
 
88
  prompt = f"""
@@ -116,6 +203,9 @@ Here is the External (Bank or Vendor) data:
116
  {external_data}
117
  """
118
 
 
 
 
119
  response = openai.ChatCompletion.create(
120
  model="gpt-5",
121
  messages=[
@@ -126,7 +216,10 @@ Here is the External (Bank or Vendor) data:
126
  temperature=1,
127
  )
128
 
 
 
129
  content = response.choices[0].message['content']
 
130
 
131
  html = f"""
132
  <div style="font-family: 'Segoe UI', sans-serif; line-height: 1.5;">
@@ -134,21 +227,40 @@ Here is the External (Bank or Vendor) data:
134
  <pre>{content}</pre>
135
  </div>
136
  """
 
 
 
 
 
137
  yield "βœ… Done!", html
138
 
139
  # βœ… Upload the files + result to S3
140
- upload_files_to_s3(
141
- erp_file_path=erp_file,
142
- external_file_path=external_file,
143
- content=html,
144
- bucket_name=bucket_name
145
- )
 
 
 
 
 
 
 
 
 
146
 
147
  except Exception as e:
148
- yield "❌ Error occurred", f"<h3>Error</h3><pre>{e}</pre>"
 
 
 
149
 
150
 
151
  # βœ… Gradio UI for CSV-only
 
 
152
  with gr.Blocks(css="""
153
  #company-logo {
154
  width: 25%;
@@ -193,5 +305,6 @@ with gr.Blocks(css="""
193
  inputs=[erp_file, external_file],
194
  outputs=[status, result]
195
  )
196
-
197
- iface.launch()
 
 
4
  import gradio as gr
5
  import boto3
6
  import uuid
7
+ import logging
8
+ import sys
9
+ from datetime import datetime
10
+
11
+ logging.basicConfig(
12
+ level=logging.INFO,
13
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
14
+ handlers=[
15
+ logging.StreamHandler(sys.stdout), # This will show in HF Spaces logs
16
+ logging.FileHandler('app.log', mode='a') # Also save to file
17
+ ]
18
+ )
19
 
20
+ logger = logging.getLogger(__name__)
 
 
21
 
22
+ # Log application startup
23
+ logger.info("πŸš€ Starting ERP Reconciliation Tool")
24
+ logger.info(f"πŸ“… Application started at: {datetime.now()}")
 
25
 
 
 
 
26
 
27
+ try:
28
+ openai.api_key = os.environ.get("Open_ai_key")
29
+ bucket_name = os.environ.get("Bucket_name")
30
 
31
+ if not openai.api_key:
32
+ logger.warning("⚠️ OpenAI API key not found in environment variables")
33
+ else:
34
+ logger.info("βœ… OpenAI API key loaded successfully")
35
 
36
+ if not bucket_name:
37
+ logger.warning("⚠️ S3 bucket name not found in environment variables")
38
+ else:
39
+ logger.info(f"βœ… S3 bucket configured: {bucket_name}")
40
 
41
+ except Exception as e:
42
+ logger.error(f"❌ Error loading environment variables: {e}")
 
 
43
 
44
+ try:
45
+ session = boto3.Session(
46
+ aws_access_key_id=os.getenv("access_key"),
47
+ aws_secret_access_key=os.getenv("secret_access_key")
48
+ )
49
+ logger.info("βœ… AWS session created successfully")
50
+ except Exception as e:
51
+ logger.error(f"❌ Error creating AWS session: {e}")
52
 
 
 
 
 
53
 
54
+ def upload_files_to_s3(erp_file_path, external_file_path, content, bucket_name):
55
+ logger.info(f"πŸ“€ Starting S3 upload process")
 
 
56
 
57
+ try:
58
+ s3 = session.client("s3")
59
+ session_id = str(uuid.uuid4())
60
+
61
+ logger.info(f"πŸ†” Generated session ID: {session_id}")
62
+
63
+ base_erp = os.path.splitext(os.path.basename(erp_file_path))[0]
64
+ base_bank = os.path.splitext(os.path.basename(external_file_path))[0]
65
+
66
+ # Add session ID to filenames
67
+ erp_filename = f"{base_erp}_{session_id}.csv"
68
+ bank_filename = f"{base_bank}_{session_id}.csv"
69
+ txt_filename = f"{session_id}.txt"
70
+
71
+ logger.info(f"πŸ“„ Generated filenames - ERP: {erp_filename}, Bank: {bank_filename}, Result: {txt_filename}")
72
+
73
+ # Write reconciliation output to local file
74
+ with open(txt_filename, "w", encoding="utf-8") as file:
75
+ file.write(content)
76
+ logger.info(f"βœ… Reconciliation result written to local file: {txt_filename}")
77
+
78
+ # === Separate folders by type ===
79
+ erp_s3_key = f"ERP Statements/{erp_filename}"
80
+ bank_s3_key = f"Bank Statements/{bank_filename}"
81
+ txt_s3_key = f"Reconciliation Results/{txt_filename}"
82
+
83
+ # === Combined folder for each run ===
84
+ combined_prefix = f"Combined Files/{session_id}/"
85
+ erp_combined_key = combined_prefix + erp_filename
86
+ bank_combined_key = combined_prefix + bank_filename
87
+ txt_combined_key = combined_prefix + txt_filename
88
+
89
+ # βœ… Upload to type-based folders
90
+ logger.info("πŸ“€ Uploading files to type-based S3 folders...")
91
+ s3.upload_file(erp_file_path, bucket_name, erp_s3_key)
92
+ logger.info(f"βœ… Uploaded ERP file to: {erp_s3_key}")
93
+
94
+ s3.upload_file(external_file_path, bucket_name, bank_s3_key)
95
+ logger.info(f"βœ… Uploaded Bank file to: {bank_s3_key}")
96
+
97
+ s3.upload_file(txt_filename, bucket_name, txt_s3_key)
98
+ logger.info(f"βœ… Uploaded result file to: {txt_s3_key}")
99
+
100
+ # βœ… Upload to combined folder
101
+ logger.info("πŸ“€ Uploading files to combined S3 folder...")
102
+ s3.upload_file(erp_file_path, bucket_name, erp_combined_key)
103
+ s3.upload_file(external_file_path, bucket_name, bank_combined_key)
104
+ s3.upload_file(txt_filename, bucket_name, txt_combined_key)
105
+ logger.info(f"βœ… All files uploaded to combined folder: {combined_prefix}")
106
+
107
+ # Clean up local file
108
+ os.remove(txt_filename)
109
+ logger.info(f"πŸ—‘οΈ Cleaned up local file: {txt_filename}")
110
+
111
+ upload_result = {
112
+ "erp_s3_key": erp_s3_key,
113
+ "bank_s3_key": bank_s3_key,
114
+ "result_s3_key": txt_s3_key,
115
+ "combined_keys": [erp_combined_key, bank_combined_key, txt_combined_key],
116
+ "session_id": session_id
117
+ }
118
+
119
+ logger.info(f"βœ… S3 upload process completed successfully for session: {session_id}")
120
+ return upload_result
121
 
122
+ except Exception as e:
123
+ logger.error(f"❌ Error in S3 upload process: {e}")
124
+ raise e
 
 
 
 
125
 
126
 
127
  # βœ… Extract transactions from CSV only
128
  def extract_transactions(file):
129
+ logger.info(f"πŸ“Š Processing file: {file.name}")
130
+
131
  filename = file.name.lower()
132
  if not filename.endswith(".csv"):
133
+ error_msg = f"Unsupported file format: {filename}. Please upload a CSV file only."
134
+ logger.error(f"❌ {error_msg}")
135
+ raise ValueError(error_msg)
136
 
137
  try:
138
  df = pd.read_csv(file.name)
139
+ logger.info(f"βœ… Successfully read CSV file: {file.name}")
140
+ logger.info(f"πŸ“ˆ File contains {len(df)} rows and {len(df.columns)} columns")
141
+ logger.info(f"🏷️ Column names: {list(df.columns)}")
142
+
143
  return df.to_string(index=False)
144
  except Exception as e:
145
+ error_msg = f"Error processing {file.name}: {e}"
146
+ logger.error(f"❌ {error_msg}")
147
+ raise ValueError(error_msg)
148
 
149
 
150
  # βœ… Reconcile the statements using OpenAI
151
  def reconcile_statements_openai(erp_file, external_file):
152
+ session_start = datetime.now()
153
+ logger.info(f"πŸ” Starting reconciliation process at: {session_start}")
154
+
155
+ # Validate inputs
156
+ if not erp_file or not external_file:
157
+ error_msg = "Both ERP and External files are required"
158
+ logger.error(f"❌ {error_msg}")
159
+ yield "❌ Error: Missing files", f"<h3>Error</h3><pre>{error_msg}</pre>"
160
+ return
161
+
162
+ logger.info(f"πŸ“ ERP file: {erp_file.name if erp_file else 'None'}")
163
+ logger.info(f"🏦 External file: {external_file.name if external_file else 'None'}")
164
+
165
  yield "⏳ Processing your request...", ""
166
 
167
  try:
168
+ # Extract data from files
169
+ logger.info("πŸ“Š Extracting data from ERP file...")
170
  erp_data = extract_transactions(erp_file)
171
+
172
+ logger.info("πŸ“Š Extracting data from External file...")
173
  external_data = extract_transactions(external_file)
174
 
175
  prompt = f"""
 
203
  {external_data}
204
  """
205
 
206
+ logger.info("πŸ€– Sending request to OpenAI...")
207
+ logger.info(f"πŸ“ Prompt length: {len(prompt)} characters")
208
+
209
  response = openai.ChatCompletion.create(
210
  model="gpt-5",
211
  messages=[
 
216
  temperature=1,
217
  )
218
 
219
+ logger.info("βœ… Received response from OpenAI")
220
+
221
  content = response.choices[0].message['content']
222
+ logger.info(f"πŸ“„ Response length: {len(content)} characters")
223
 
224
  html = f"""
225
  <div style="font-family: 'Segoe UI', sans-serif; line-height: 1.5;">
 
227
  <pre>{content}</pre>
228
  </div>
229
  """
230
+
231
+ # Calculate processing time
232
+ processing_time = (datetime.now() - session_start).total_seconds()
233
+ logger.info(f"⏱️ Processing completed in {processing_time:.2f} seconds")
234
+
235
  yield "βœ… Done!", html
236
 
237
  # βœ… Upload the files + result to S3
238
+ try:
239
+ logger.info("πŸ“€ Starting S3 upload...")
240
+ upload_result = upload_files_to_s3(
241
+ erp_file_path=erp_file.name,
242
+ external_file_path=external_file.name,
243
+ content=html,
244
+ bucket_name=bucket_name
245
+ )
246
+ logger.info(f"βœ… Files uploaded successfully with session ID: {upload_result['session_id']}")
247
+ except Exception as upload_error:
248
+ logger.error(f"❌ S3 upload failed: {upload_error}")
249
+ # Don't fail the entire process if S3 upload fails
250
+ logger.info("⚠️ Continuing despite S3 upload failure")
251
+
252
+ logger.info(f"πŸŽ‰ Reconciliation process completed successfully!")
253
 
254
  except Exception as e:
255
+ error_msg = f"Error during reconciliation: {e}"
256
+ logger.error(f"❌ {error_msg}")
257
+ logger.error(f"πŸ› Full error details: {str(e)}")
258
+ yield "❌ Error occurred", f"<h3>Error</h3><pre>{error_msg}</pre>"
259
 
260
 
261
  # βœ… Gradio UI for CSV-only
262
+ logger.info("🎨 Building Gradio interface...")
263
+
264
  with gr.Blocks(css="""
265
  #company-logo {
266
  width: 25%;
 
305
  inputs=[erp_file, external_file],
306
  outputs=[status, result]
307
  )
308
+ iface.launch()
309
+ # Log when interface is ready
310
+ logger.info("βœ… Gradio interface built successfully")