mou3az commited on
Commit
ea950da
·
verified ·
1 Parent(s): cb68e32

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +615 -244
app.py CHANGED
@@ -22,6 +22,8 @@ import openpyxl
22
  import pptx
23
  import PyPDF2
24
  import requests
 
 
25
  from youtube_transcript_api import YouTubeTranscriptApi
26
  from youtube_transcript_api._errors import (
27
  NoTranscriptFound,
@@ -46,9 +48,7 @@ def read_csv(file_path):
46
  csv_reader = csv.reader(csvfile)
47
  csv_data = [row for row in csv_reader]
48
 
49
- return ' '.join(
50
- [' '.join(row) for row in csv_data]
51
- )
52
 
53
 
54
  def read_text(file_path):
@@ -80,8 +80,7 @@ def read_docx(file_path):
80
  doc = docx.Document(file_path)
81
 
82
  return '\n'.join(
83
- paragraph.text
84
- for paragraph in doc.paragraphs
85
  )
86
 
87
 
@@ -105,9 +104,7 @@ def read_xlsx(file_path):
105
  for row in sheet.iter_rows(values_only=True):
106
  text_data += (
107
  ' '.join(
108
- str(cell)
109
- for cell in row
110
- if cell is not None
111
  )
112
  + '\n'
113
  )
@@ -119,10 +116,7 @@ def read_json(file_path):
119
  with open(file_path, 'r', encoding='utf-8') as f:
120
  json_data = json.load(f)
121
 
122
- return json.dumps(
123
- json_data,
124
- ensure_ascii=False
125
- )
126
 
127
 
128
  def read_html(file_path):
@@ -154,50 +148,38 @@ def read_xml(file_path):
154
  )
155
 
156
 
157
- def clean_url_input(url):
158
  if not url:
159
- return ''
160
 
161
  url = str(url).strip()
162
 
163
  url = url.replace('\\n', '')
164
  url = url.replace('\n', '')
165
- url = url.replace('\r', '')
166
-
167
- markdown_match = re.search(
168
- r'\]\((https?://[^)\s]+)\)',
169
- url
170
- )
171
-
172
- if markdown_match:
173
- url = markdown_match.group(1)
174
 
175
  markdown_match = re.search(
176
- r'\[?(https?://[^\]\s]+)\]?',
177
- url
 
178
  )
179
 
180
  if markdown_match:
181
  url = markdown_match.group(1)
182
 
183
- url = url.replace('\\', '')
184
-
185
- url = url.strip()
186
-
187
- url = url.rstrip(
188
- '.,!?;:)]}'
189
  )
190
 
191
- return url
192
-
193
-
194
- def extract_youtube_video_id(url):
195
- if not url:
196
- return None
197
 
198
- url = clean_url_input(url)
199
 
200
  parsed = urlparse(url)
 
201
  hostname = (
202
  parsed.hostname or ''
203
  ).lower()
@@ -212,13 +194,7 @@ def extract_youtube_video_id(url):
212
  .split('/')[0]
213
  )
214
 
215
- if re.fullmatch(
216
- r'[A-Za-z0-9_-]{11}',
217
- video_id
218
- ):
219
- return video_id
220
-
221
- return None
222
 
223
  if hostname in (
224
  'youtube.com',
@@ -227,43 +203,38 @@ def extract_youtube_video_id(url):
227
  ):
228
 
229
  if parsed.path == '/watch':
 
230
  video_ids = parse_qs(
231
  parsed.query
232
  ).get('v')
233
 
234
- if not video_ids:
235
- return None
236
-
237
- video_id = video_ids[0]
238
 
239
- if re.fullmatch(
240
- r'[A-Za-z0-9_-]{11}',
241
- video_id
242
- ):
243
- return video_id
244
 
245
- return None
246
 
247
  for prefix in (
248
  '/shorts/',
249
  '/embed/',
250
  '/live/'
251
  ):
 
252
  if parsed.path.startswith(prefix):
 
253
  video_id = (
254
  parsed.path[
255
  len(prefix):
256
  ]
257
  .split('/')[0]
 
258
  )
259
 
260
- if re.fullmatch(
261
- r'[A-Za-z0-9_-]{11}',
262
- video_id
263
- ):
264
- return video_id
265
-
266
- return None
267
 
268
  return None
269
 
@@ -275,47 +246,108 @@ def is_youtube_url(url):
275
  )
276
 
277
 
278
- def fetch_transcript_text(
279
- video_id,
280
- lang
281
- ):
282
- if hasattr(
283
- YouTubeTranscriptApi,
284
- 'get_transcript'
285
- ):
286
- transcript = (
287
- YouTubeTranscriptApi
288
- .get_transcript(
289
- video_id,
290
- languages=[lang]
291
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  )
293
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  return ' '.join(
295
- entry['text']
296
- for entry in transcript
297
  )
298
 
299
- ytt_api = YouTubeTranscriptApi()
 
 
 
 
300
 
301
- fetched = ytt_api.fetch(
302
- video_id,
303
- languages=[lang]
304
- )
305
 
306
- return ' '.join(
307
- snippet.text
308
- for snippet in fetched
309
- )
310
 
 
 
 
 
311
 
312
- def process_youtube_video(
313
- url,
314
- languages=['en', 'ar']
315
- ):
316
  video_id = extract_youtube_video_id(url)
317
 
318
  if not video_id:
 
319
  return (
320
  'Invalid YouTube video URL. '
321
  'Please provide a valid YouTube video link.'
@@ -326,67 +358,61 @@ def process_youtube_video(
326
  repr(video_id)
327
  )
328
 
329
- transcript_data = []
330
- errors = []
331
 
332
- for lang in languages:
333
- try:
334
- transcript = (
335
- fetch_transcript_text(
336
- video_id,
337
- lang
338
- )
339
- )
340
 
341
- if transcript:
342
- transcript_data.append(
343
- transcript
344
- )
345
 
346
- except (
347
- NoTranscriptFound,
348
- TranscriptsDisabled,
349
- VideoUnavailable
350
- ) as e:
351
 
352
- errors.append(
353
- f'{lang}: {type(e).__name__}'
354
- )
 
355
 
356
- except Exception as e:
357
 
358
- print(
359
- f'YOUTUBE TRANSCRIPT ERROR [{lang}]:',
360
- repr(e)
361
- )
362
 
363
- errors.append(
364
- f'{lang}: {str(e)}'
365
- )
366
 
367
- if transcript_data:
368
- return ' '.join(
369
- transcript_data
370
  )
371
 
372
- print(
373
- 'YOUTUBE TRANSCRIPT ERRORS:',
374
- repr(errors)
375
- )
376
 
377
- return (
378
- 'Unable to retrieve a transcript for '
379
- 'this YouTube video. The video may not '
380
- 'have English or Arabic captions, '
381
- 'captions may be disabled, or YouTube '
382
- 'may be blocking transcript access from '
383
- 'this server.'
384
- )
 
 
 
 
 
 
 
 
 
385
 
386
 
387
  def read_web_page(url):
 
388
  try:
389
- url = clean_url_input(url)
 
390
 
391
  response = requests.get(
392
  url,
@@ -404,6 +430,7 @@ def read_web_page(url):
404
  )
405
 
406
  if response.status_code >= 400:
 
407
  return (
408
  'Unable to access webpage. '
409
  f'HTTP status: {response.status_code}'
@@ -416,6 +443,7 @@ def read_web_page(url):
416
  )
417
 
418
  if 'text/plain' in content_type:
 
419
  return response.text
420
 
421
  src = response.text
@@ -431,6 +459,7 @@ def read_web_page(url):
431
  'noscript',
432
  'svg'
433
  ]):
 
434
  element.decompose()
435
 
436
  text_data = soup.get_text(
@@ -444,26 +473,27 @@ def read_web_page(url):
444
  )
445
 
446
  if not text_data:
 
447
  return (
448
- 'The webpage was accessed '
449
- 'successfully but contains no '
450
- 'readable text.'
451
  )
452
 
453
  return text_data
454
 
455
  except requests.exceptions.Timeout:
 
456
  return (
457
  'The webpage request timed out. '
458
  'Please try another link.'
459
  )
460
 
461
  except requests.exceptions.RequestException as e:
462
- return (
463
- f'Unable to access webpage: {e}'
464
- )
465
 
466
  except Exception as e:
 
467
  return (
468
  'An error occurred while reading '
469
  f'the webpage: {e}'
@@ -474,7 +504,9 @@ def read_data(
474
  file_path_or_url,
475
  languages=['en', 'ar']
476
  ):
 
477
  if not file_path_or_url:
 
478
  return 'Unsupported type or format.'
479
 
480
  file_path_or_url = str(
@@ -484,14 +516,15 @@ def read_data(
484
  if is_youtube_url(
485
  file_path_or_url
486
  ):
 
487
  return process_youtube_video(
488
- file_path_or_url,
489
- languages
490
  )
491
 
492
  if file_path_or_url.startswith(
493
  ('http://', 'https://')
494
  ):
 
495
  return read_web_page(
496
  file_path_or_url
497
  )
@@ -501,46 +534,55 @@ def read_data(
501
  )
502
 
503
  if lower_path.endswith('.csv'):
 
504
  return read_csv(
505
  file_path_or_url
506
  )
507
 
508
  elif lower_path.endswith('.txt'):
 
509
  return read_text(
510
  file_path_or_url
511
  )
512
 
513
  elif lower_path.endswith('.pdf'):
 
514
  return read_pdf(
515
  file_path_or_url
516
  )
517
 
518
  elif lower_path.endswith('.docx'):
 
519
  return read_docx(
520
  file_path_or_url
521
  )
522
 
523
  elif lower_path.endswith('.pptx'):
 
524
  return read_pptx(
525
  file_path_or_url
526
  )
527
 
528
  elif lower_path.endswith('.xlsx'):
 
529
  return read_xlsx(
530
  file_path_or_url
531
  )
532
 
533
  elif lower_path.endswith('.json'):
 
534
  return read_json(
535
  file_path_or_url
536
  )
537
 
538
  elif lower_path.endswith('.html'):
 
539
  return read_html(
540
  file_path_or_url
541
  )
542
 
543
  elif lower_path.endswith('.xml'):
 
544
  return read_xml(
545
  file_path_or_url
546
  )
@@ -549,11 +591,22 @@ def read_data(
549
 
550
 
551
  def normalize_text(text):
552
- if not isinstance(text, str):
 
 
 
 
 
553
  text = str(text)
554
 
555
  text = re.sub(
556
- r'\*+',
 
 
 
 
 
 
557
  '',
558
  text
559
  )
@@ -566,6 +619,7 @@ def normalize_text(text):
566
  )
567
 
568
  for punc in punctuation:
 
569
  text = text.replace(
570
  punc,
571
  ''
@@ -577,7 +631,9 @@ def normalize_text(text):
577
  text
578
  )
579
 
580
- words = word_tokenize(text)
 
 
581
 
582
  return ' '.join(words)
583
 
@@ -593,18 +649,22 @@ llm = HuggingFaceEndpoint(
593
  do_sample=True,
594
  )
595
 
 
596
  chat_model = ChatHuggingFace(
597
  llm=llm
598
  )
599
 
 
600
  model_name = (
601
  'sentence-transformers/all-mpnet-base-v2'
602
  )
603
 
 
604
  embedding_llm = HuggingFaceEmbeddings(
605
  model_name=model_name
606
  )
607
 
 
608
  db = FAISS.load_local(
609
  'faiss_index',
610
  embedding_llm,
@@ -612,7 +672,10 @@ db = FAISS.load_local(
612
  )
613
 
614
 
615
- def print_like_dislike(x: gr.LikeData):
 
 
 
616
  print(
617
  x.index,
618
  x.value,
@@ -624,7 +687,9 @@ def user(
624
  user_message,
625
  history
626
  ):
 
627
  if not len(user_message):
 
628
  raise gr.Error(
629
  'Chat messages cannot be empty'
630
  )
@@ -642,24 +707,29 @@ def user2(
642
  history,
643
  link
644
  ):
645
- if not len(user_message) or not len(link):
 
 
 
 
 
646
  raise gr.Error(
647
  'Chat messages or links cannot be empty'
648
  )
649
 
650
- link = clean_url_input(link)
651
  user_message = str(
652
  user_message
653
  ).strip()
654
 
655
- if not link:
656
- raise gr.Error(
657
- 'Please provide a valid URL.'
658
- )
659
 
660
  history.append({
661
  'role': 'user',
662
- 'content': user_message
663
  })
664
 
665
  return '', history, link
@@ -670,13 +740,19 @@ def user3(
670
  history,
671
  file_path
672
  ):
673
- if not len(user_message) or not file_path:
 
 
 
 
 
674
  raise gr.Error(
675
  'Chat messages or files cannot be empty'
676
  )
677
 
678
  combined_message = (
679
- f'{file_path}\n{user_message}'
 
680
  )
681
 
682
  history.append({
@@ -707,6 +783,7 @@ def Chat_Message(
707
  history,
708
  messages1
709
  ):
 
710
  user_msg_text = history[-1]['content']
711
 
712
  message = HumanMessage(
@@ -717,19 +794,25 @@ def Chat_Message(
717
  messages1[-1],
718
  HumanMessage
719
  ):
 
720
  messages1 = messages1[:-2]
721
 
722
- messages1.append(message)
 
 
723
 
724
  if len(messages1) >= 8:
 
725
  messages1 = messages1[-8:]
726
 
727
  try:
 
728
  response = chat_model.invoke(
729
  messages1
730
  )
731
 
732
  except Exception as e:
 
733
  error_message = str(e)
734
 
735
  print(
@@ -737,18 +820,23 @@ def Chat_Message(
737
  repr(e)
738
  )
739
 
740
- start_index = error_message.find(
741
- 'Input validation error:'
 
 
742
  )
743
 
744
- end_index = error_message.find(
745
- 'and 4096 `max_new_tokens`'
 
 
746
  )
747
 
748
  if (
749
  start_index != -1
750
  and end_index != -1
751
  ):
 
752
  raise gr.Error(
753
  error_message[
754
  start_index:end_index
@@ -771,9 +859,12 @@ def Chat_Message(
771
  })
772
 
773
  for character in response.content:
 
774
  history[-1]['content'] += character
775
 
776
- time.sleep(0.0025)
 
 
777
 
778
  yield history, messages1
779
 
@@ -782,6 +873,7 @@ def Internet_Search(
782
  history,
783
  messages2
784
  ):
 
785
  message = str(
786
  history[-1]['content']
787
  )
@@ -790,6 +882,7 @@ def Internet_Search(
790
  messages2[-1],
791
  HumanMessage
792
  ):
 
793
  messages2 = messages2[:-2]
794
 
795
  similar_docs = db.similarity_search(
@@ -798,11 +891,16 @@ def Internet_Search(
798
  )
799
 
800
  if similar_docs:
 
801
  source_knowledge = '\n'.join(
802
- x.page_content
803
- for x in similar_docs
 
 
804
  )
 
805
  else:
 
806
  source_knowledge = ''
807
 
808
  augmented_prompt = f"""
@@ -827,17 +925,22 @@ information from other sources.
827
  content=augmented_prompt
828
  )
829
 
830
- messages2.append(msg)
 
 
831
 
832
  if len(messages2) >= 4:
 
833
  messages2 = messages2[-4:]
834
 
835
  try:
 
836
  response = chat_model.invoke(
837
  messages2
838
  )
839
 
840
  except Exception as e:
 
841
  error_message = str(e)
842
 
843
  print(
@@ -845,18 +948,23 @@ information from other sources.
845
  repr(e)
846
  )
847
 
848
- start_index = error_message.find(
849
- 'Input validation error:'
 
 
850
  )
851
 
852
- end_index = error_message.find(
853
- 'and 4096 `max_new_tokens`'
 
 
854
  )
855
 
856
  if (
857
  start_index != -1
858
  and end_index != -1
859
  ):
 
860
  raise gr.Error(
861
  error_message[
862
  start_index:end_index
@@ -879,9 +987,12 @@ information from other sources.
879
  })
880
 
881
  for character in response.content:
 
882
  history[-1]['content'] += character
883
 
884
- time.sleep(0.0025)
 
 
885
 
886
  yield history, messages2
887
 
@@ -889,6 +1000,7 @@ information from other sources.
889
  def generate_chart_config(
890
  description
891
  ):
 
892
  system_instructions = """
893
  You are a Chart.js configuration generator.
894
 
@@ -980,7 +1092,11 @@ Rules:
980
  start = raw.find('{')
981
  end = raw.rfind('}')
982
 
983
- if start == -1 or end == -1:
 
 
 
 
984
  raise ValueError(
985
  'Model did not return a JSON object.\n'
986
  f'Raw response:\n{raw}'
@@ -995,24 +1111,30 @@ Rules:
995
  raw
996
  )
997
 
998
- config = json.loads(raw)
 
 
999
 
1000
  if 'type' not in config:
 
1001
  raise ValueError(
1002
  "Chart config missing 'type'"
1003
  )
1004
 
1005
  if 'data' not in config:
 
1006
  raise ValueError(
1007
  "Chart config missing 'data'"
1008
  )
1009
 
1010
  if 'labels' not in config['data']:
 
1011
  raise ValueError(
1012
  "Chart config missing 'data.labels'"
1013
  )
1014
 
1015
  if 'datasets' not in config['data']:
 
1016
  raise ValueError(
1017
  "Chart config missing 'data.datasets'"
1018
  )
@@ -1021,6 +1143,7 @@ Rules:
1021
  config['data']['datasets'],
1022
  list
1023
  ):
 
1024
  raise ValueError(
1025
  "'data.datasets' must be a list"
1026
  )
@@ -1032,6 +1155,7 @@ def Chart_Generator(
1032
  history,
1033
  messages3
1034
  ):
 
1035
  message = str(
1036
  history[-1]['content']
1037
  )
@@ -1040,6 +1164,7 @@ def Chart_Generator(
1040
  messages3[-1],
1041
  HumanMessage
1042
  ):
 
1043
  messages3 = messages3[:-2]
1044
 
1045
  if '#chart' in message.lower():
@@ -1052,14 +1177,17 @@ def Chart_Generator(
1052
  )[1].strip()
1053
 
1054
  if not chart_description:
 
1055
  combined_content = (
1056
  'Please provide chart details after #chart.'
1057
  )
1058
 
1059
  else:
 
1060
  chart_config = None
1061
 
1062
  try:
 
1063
  chart_config = (
1064
  generate_chart_config(
1065
  chart_description
@@ -1075,6 +1203,7 @@ def Chart_Generator(
1075
  )
1076
 
1077
  except Exception as e:
 
1078
  print(
1079
  'CHART GENERATION ERROR:',
1080
  repr(e)
@@ -1085,10 +1214,10 @@ def Chart_Generator(
1085
  f'Error: {str(e)}'
1086
  )
1087
 
1088
- chart_config = None
1089
-
1090
  if chart_config:
 
1091
  try:
 
1092
  config_json = json.dumps(
1093
  chart_config,
1094
  separators=(',', ':')
@@ -1122,20 +1251,25 @@ def Chart_Generator(
1122
  chart_response.status_code
1123
  )
1124
 
1125
- if chart_response.status_code != 200:
 
 
 
 
1126
  print(
1127
  'QUICKCHART RESPONSE:',
1128
  chart_response.text[:1000]
1129
  )
1130
 
1131
  combined_content = (
1132
- 'QuickChart failed to '
1133
- 'generate the chart.\n\n'
1134
  f'HTTP Status: '
1135
  f'{chart_response.status_code}'
1136
  )
1137
 
1138
  else:
 
1139
  image_html = (
1140
  f'<img src="{chart_url}" '
1141
  'alt="Generated Chart" '
@@ -1146,8 +1280,8 @@ def Chart_Generator(
1146
  )
1147
 
1148
  chart_summary_prompt = (
1149
- 'The following Chart.js '
1150
- 'configuration was generated:\n\n'
1151
  f'{json.dumps(chart_config, indent=2)}\n\n'
1152
  'Briefly describe what this chart '
1153
  'represents.'
@@ -1167,6 +1301,7 @@ def Chart_Generator(
1167
  ]
1168
 
1169
  try:
 
1170
  response = (
1171
  chat_model.invoke(
1172
  analysis_messages
@@ -1178,6 +1313,7 @@ def Chart_Generator(
1178
  )
1179
 
1180
  except Exception as e:
 
1181
  print(
1182
  'CHART ANALYSIS ERROR:',
1183
  repr(e)
@@ -1193,6 +1329,7 @@ def Chart_Generator(
1193
  )
1194
 
1195
  except Exception as e:
 
1196
  print(
1197
  'QUICKCHART REQUEST ERROR:',
1198
  repr(e)
@@ -1205,21 +1342,27 @@ def Chart_Generator(
1205
  )
1206
 
1207
  else:
 
1208
  prompt = HumanMessage(
1209
  content=message
1210
  )
1211
 
1212
- messages3.append(prompt)
 
 
1213
 
1214
  if len(messages3) >= 6:
 
1215
  messages3 = messages3[-6:]
1216
 
1217
  try:
 
1218
  response = chat_model.invoke(
1219
  messages3
1220
  )
1221
 
1222
  except Exception as e:
 
1223
  error_message = str(e)
1224
 
1225
  print(
@@ -1227,18 +1370,23 @@ def Chart_Generator(
1227
  repr(e)
1228
  )
1229
 
1230
- start_index = error_message.find(
1231
- 'Input validation error:'
 
 
1232
  )
1233
 
1234
- end_index = error_message.find(
1235
- 'and 4096 `max_new_tokens`'
 
 
1236
  )
1237
 
1238
  if (
1239
  start_index != -1
1240
  and end_index != -1
1241
  ):
 
1242
  raise gr.Error(
1243
  error_message[
1244
  start_index:end_index
@@ -1255,7 +1403,9 @@ def Chart_Generator(
1255
  )
1256
  )
1257
 
1258
- combined_content = response.content
 
 
1259
 
1260
  history.append({
1261
  'role': 'assistant',
@@ -1263,27 +1413,72 @@ def Chart_Generator(
1263
  })
1264
 
1265
  for character in combined_content:
 
1266
  history[-1]['content'] += character
1267
 
1268
- time.sleep(0.0025)
 
 
1269
 
1270
  yield history, messages3
1271
 
1272
 
1273
  def extract_url_from_text(text):
 
1274
  if not text:
 
1275
  return None
1276
 
1277
- text = str(text).strip()
 
 
 
 
 
1278
 
1279
- text = text.replace(
1280
- '\\n',
1281
- ''
1282
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
 
1284
  text = text.replace(
1285
- '\n',
1286
- ''
1287
  )
1288
 
1289
  text = text.replace(
@@ -1291,53 +1486,160 @@ def extract_url_from_text(text):
1291
  ''
1292
  )
1293
 
1294
- markdown_match = re.search(
1295
- r'\]\((https?://[^)\s]+)\)',
1296
- text
 
1297
  )
1298
 
1299
- if markdown_match:
1300
- return (
1301
- markdown_match
1302
- .group(1)
1303
- .rstrip('.,!?;:)]}')
1304
  )
1305
 
1306
- url_match = re.search(
1307
  r'https?://[^\s<>"\']+',
1308
- text
 
1309
  )
1310
 
1311
- if url_match:
1312
- return (
1313
- url_match
1314
- .group(0)
1315
- .rstrip('.,!?;:)]}')
 
1316
  )
1317
 
1318
  return None
1319
 
1320
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1321
  def Link_Scratch(
1322
  history,
1323
- messages4,
1324
- link
1325
  ):
1326
- user_message = str(
1327
- history[-1]['content']
1328
- ).strip()
1329
 
1330
- link = clean_url_input(link)
 
 
1331
 
1332
  if isinstance(
1333
  messages4[-1],
1334
  HumanMessage
1335
  ):
 
1336
  messages4 = messages4[:-2]
1337
 
 
 
 
 
 
 
 
 
 
 
 
1338
  print(
1339
- 'USER QUERY:',
1340
- repr(user_message)
1341
  )
1342
 
1343
  print(
@@ -1345,14 +1647,23 @@ def Link_Scratch(
1345
  repr(link)
1346
  )
1347
 
 
 
 
 
 
1348
  if not link:
 
1349
  response_message = (
1350
- 'Please provide a valid URL starting '
1351
- 'with http:// or https://'
1352
  )
1353
 
1354
  else:
1355
- result = read_data(link)
 
 
 
1356
 
1357
  print(
1358
  'LINK READ RESULT TYPE:',
@@ -1373,7 +1684,10 @@ def Link_Scratch(
1373
  ]
1374
 
1375
  if (
1376
- isinstance(result, str)
 
 
 
1377
  and (
1378
  result in error_results
1379
  or result.startswith(
@@ -1382,22 +1696,38 @@ def Link_Scratch(
1382
  or result.startswith(
1383
  'An error occurred while reading'
1384
  )
 
 
 
 
 
 
 
 
 
 
 
 
1385
  )
1386
  ):
 
1387
  response_message = result
1388
 
1389
  else:
 
1390
  content_data = normalize_text(
1391
  result
1392
  )
1393
 
1394
  if not content_data:
 
1395
  response_message = (
1396
  'The provided link is empty or '
1397
  'does not contain any meaningful words.'
1398
  )
1399
 
1400
  else:
 
1401
  augmented_prompt = f"""
1402
  You are an AI designed to help understand
1403
  and extract information from provided Link Content.
@@ -1410,9 +1740,9 @@ Query:
1410
  Link Content:
1411
  {content_data}
1412
 
1413
- If the query is not related to specific Link Content,
1414
- engage in general conversation or provide relevant
1415
- information from other sources.
1416
  """
1417
 
1418
  message = HumanMessage(
@@ -1426,13 +1756,13 @@ information from other sources.
1426
  messages4 = messages4[-1:]
1427
 
1428
  try:
1429
- response = (
1430
- chat_model.invoke(
1431
- messages4
1432
- )
1433
  )
1434
 
1435
  except Exception as e:
 
1436
  error_message = str(e)
1437
 
1438
  print(
@@ -1456,6 +1786,7 @@ information from other sources.
1456
  start_index != -1
1457
  and end_index != -1
1458
  ):
 
1459
  raise gr.Error(
1460
  error_message[
1461
  start_index:end_index
@@ -1482,9 +1813,12 @@ information from other sources.
1482
  })
1483
 
1484
  for character in response_message:
 
1485
  history[-1]['content'] += character
1486
 
1487
- time.sleep(0.0025)
 
 
1488
 
1489
  yield history, messages4
1490
 
@@ -1493,6 +1827,7 @@ def insert_line_breaks(
1493
  text,
1494
  every=8
1495
  ):
 
1496
  return '\n'.join(
1497
  text[i:i + every]
1498
  for i in range(
@@ -1503,7 +1838,10 @@ def insert_line_breaks(
1503
  )
1504
 
1505
 
1506
- def display_file_name(file):
 
 
 
1507
  supported_extensions = [
1508
  '.csv',
1509
  '.txt',
@@ -1524,6 +1862,7 @@ def display_file_name(file):
1524
  file_extension.lower()
1525
  in supported_extensions
1526
  ):
 
1527
  file_name = os.path.basename(
1528
  file.name
1529
  )
@@ -1565,6 +1904,7 @@ def File_Interact(
1565
  filepath,
1566
  messages5
1567
  ):
 
1568
  combined_message = str(
1569
  history[-1]['content']
1570
  )
@@ -1573,12 +1913,14 @@ def File_Interact(
1573
  messages5[-1],
1574
  HumanMessage
1575
  ):
 
1576
  messages5 = messages5[:-2]
1577
 
1578
  link = ''
1579
  user_message = ''
1580
 
1581
  if '\n' in combined_message:
 
1582
  link, user_message = (
1583
  combined_message.split(
1584
  '\n',
@@ -1586,27 +1928,33 @@ def File_Interact(
1586
  )
1587
  )
1588
 
1589
- user_message = user_message.strip()
 
 
1590
 
1591
  result = read_data(
1592
  filepath
1593
  )
1594
 
1595
  if result == 'Unsupported type or format.':
 
1596
  response_message = result
1597
 
1598
  else:
 
1599
  content_data = normalize_text(
1600
  result
1601
  )
1602
 
1603
  if not content_data:
 
1604
  response_message = (
1605
  'The file is empty or does not '
1606
  'contain any meaningful words.'
1607
  )
1608
 
1609
  else:
 
1610
  augmented_prompt = f"""
1611
  You are an AI designed to help understand
1612
  and extract information from provided File Content.
@@ -1636,6 +1984,7 @@ information from other sources.
1636
  messages5 = messages5[-1:]
1637
 
1638
  try:
 
1639
  response = (
1640
  chat_model.invoke(
1641
  messages5
@@ -1643,6 +1992,7 @@ information from other sources.
1643
  )
1644
 
1645
  except Exception as e:
 
1646
  error_message = str(e)
1647
 
1648
  print(
@@ -1666,6 +2016,7 @@ information from other sources.
1666
  start_index != -1
1667
  and end_index != -1
1668
  ):
 
1669
  raise gr.Error(
1670
  error_message[
1671
  start_index:end_index
@@ -1692,9 +2043,12 @@ information from other sources.
1692
  })
1693
 
1694
  for character in response_message:
 
1695
  history[-1]['content'] += character
1696
 
1697
- time.sleep(0.0025)
 
 
1698
 
1699
  yield history, messages5
1700
 
@@ -1703,12 +2057,14 @@ def Explore_WebSite(
1703
  history,
1704
  messages6
1705
  ):
 
1706
  message = history[-1]['content']
1707
 
1708
  if isinstance(
1709
  messages6[-1],
1710
  HumanMessage
1711
  ):
 
1712
  messages6 = messages6[:-2]
1713
 
1714
  links = [
@@ -1716,8 +2072,10 @@ def Explore_WebSite(
1716
  ]
1717
 
1718
  result = '\n'.join(
1719
- read_data(link)
1720
- for link in links
 
 
1721
  )
1722
 
1723
  content_data = normalize_text(
@@ -1746,17 +2104,22 @@ information from other sources.
1746
  content=augmented_prompt
1747
  )
1748
 
1749
- messages6.append(msg)
 
 
1750
 
1751
  if len(messages6) >= 4:
 
1752
  messages6 = messages6[-4:]
1753
 
1754
  try:
 
1755
  response = chat_model.invoke(
1756
  messages6
1757
  )
1758
 
1759
  except Exception as e:
 
1760
  error_message = str(e)
1761
 
1762
  print(
@@ -1764,18 +2127,23 @@ information from other sources.
1764
  repr(e)
1765
  )
1766
 
1767
- start_index = error_message.find(
1768
- 'Input validation error:'
 
 
1769
  )
1770
 
1771
- end_index = error_message.find(
1772
- 'and 4096 `max_new_tokens`'
 
 
1773
  )
1774
 
1775
  if (
1776
  start_index != -1
1777
  and end_index != -1
1778
  ):
 
1779
  raise gr.Error(
1780
  error_message[
1781
  start_index:end_index
@@ -1798,9 +2166,12 @@ information from other sources.
1798
  })
1799
 
1800
  for character in response.content:
 
1801
  history[-1]['content'] += character
1802
 
1803
- time.sleep(0.0025)
 
 
1804
 
1805
  yield history, messages6
1806
 
@@ -2094,7 +2465,7 @@ with gr.Blocks() as demo:
2094
  queue=True
2095
  ).then(
2096
  Link_Scratch,
2097
- [chatbot, messages4, msg1],
2098
  [chatbot, messages4]
2099
  )
2100
 
@@ -2105,7 +2476,7 @@ with gr.Blocks() as demo:
2105
  queue=True
2106
  ).then(
2107
  Link_Scratch,
2108
- [chatbot, messages4, msg1],
2109
  [chatbot, messages4]
2110
  )
2111
 
@@ -2116,7 +2487,7 @@ with gr.Blocks() as demo:
2116
  queue=True
2117
  ).then(
2118
  Link_Scratch,
2119
- [chatbot, messages4, msg1],
2120
  [chatbot, messages4]
2121
  )
2122
 
 
22
  import pptx
23
  import PyPDF2
24
  import requests
25
+ from requests.adapters import HTTPAdapter
26
+ from urllib3.util.retry import Retry
27
  from youtube_transcript_api import YouTubeTranscriptApi
28
  from youtube_transcript_api._errors import (
29
  NoTranscriptFound,
 
48
  csv_reader = csv.reader(csvfile)
49
  csv_data = [row for row in csv_reader]
50
 
51
+ return ' '.join([' '.join(row) for row in csv_data])
 
 
52
 
53
 
54
  def read_text(file_path):
 
80
  doc = docx.Document(file_path)
81
 
82
  return '\n'.join(
83
+ [paragraph.text for paragraph in doc.paragraphs]
 
84
  )
85
 
86
 
 
104
  for row in sheet.iter_rows(values_only=True):
105
  text_data += (
106
  ' '.join(
107
+ [str(cell) for cell in row if cell is not None]
 
 
108
  )
109
  + '\n'
110
  )
 
116
  with open(file_path, 'r', encoding='utf-8') as f:
117
  json_data = json.load(f)
118
 
119
+ return json.dumps(json_data, ensure_ascii=False)
 
 
 
120
 
121
 
122
  def read_html(file_path):
 
148
  )
149
 
150
 
151
+ def extract_youtube_video_id(url):
152
  if not url:
153
+ return None
154
 
155
  url = str(url).strip()
156
 
157
  url = url.replace('\\n', '')
158
  url = url.replace('\n', '')
159
+ url = url.replace('\\', '')
 
 
 
 
 
 
 
 
160
 
161
  markdown_match = re.search(
162
+ r'\]\(\s*(https?://[^)\s]+)',
163
+ url,
164
+ flags=re.IGNORECASE
165
  )
166
 
167
  if markdown_match:
168
  url = markdown_match.group(1)
169
 
170
+ url_match = re.search(
171
+ r'https?://(?:www\.)?(?:youtube\.com|youtu\.be)[^\s<>"\']+',
172
+ url,
173
+ flags=re.IGNORECASE
 
 
174
  )
175
 
176
+ if url_match:
177
+ url = url_match.group(0)
 
 
 
 
178
 
179
+ url = url.rstrip('.,!?;:)]}')
180
 
181
  parsed = urlparse(url)
182
+
183
  hostname = (
184
  parsed.hostname or ''
185
  ).lower()
 
194
  .split('/')[0]
195
  )
196
 
197
+ return video_id or None
 
 
 
 
 
 
198
 
199
  if hostname in (
200
  'youtube.com',
 
203
  ):
204
 
205
  if parsed.path == '/watch':
206
+
207
  video_ids = parse_qs(
208
  parsed.query
209
  ).get('v')
210
 
211
+ if video_ids:
 
 
 
212
 
213
+ video_id = (
214
+ video_ids[0]
215
+ .split('&')[0]
216
+ .strip()
217
+ )
218
 
219
+ return video_id or None
220
 
221
  for prefix in (
222
  '/shorts/',
223
  '/embed/',
224
  '/live/'
225
  ):
226
+
227
  if parsed.path.startswith(prefix):
228
+
229
  video_id = (
230
  parsed.path[
231
  len(prefix):
232
  ]
233
  .split('/')[0]
234
+ .strip()
235
  )
236
 
237
+ return video_id or None
 
 
 
 
 
 
238
 
239
  return None
240
 
 
246
  )
247
 
248
 
249
+ youtube_session = requests.Session()
250
+
251
+ youtube_session.headers.update({
252
+ 'User-Agent': (
253
+ 'Mozilla/5.0 '
254
+ '(X11; Linux x86_64) '
255
+ 'AppleWebKit/537.36 '
256
+ '(KHTML, like Gecko) '
257
+ 'Chrome/131.0.0.0 Safari/537.36'
258
+ ),
259
+ 'Accept-Language': 'en-US,en;q=0.9',
260
+ 'Accept': (
261
+ 'text/html,application/xhtml+xml,'
262
+ 'application/xml;q=0.9,image/avif,'
263
+ 'image/webp,*/*;q=0.8'
264
+ ),
265
+ 'Connection': 'close',
266
+ })
267
+
268
+ retry_strategy = Retry(
269
+ total=3,
270
+ connect=3,
271
+ read=3,
272
+ backoff_factor=1,
273
+ status_forcelist=[429, 500, 502, 503, 504],
274
+ allowed_methods=[
275
+ 'GET',
276
+ 'HEAD'
277
+ ]
278
+ )
279
+
280
+ youtube_adapter = HTTPAdapter(
281
+ max_retries=retry_strategy
282
+ )
283
+
284
+ youtube_session.mount(
285
+ 'https://',
286
+ youtube_adapter
287
+ )
288
+
289
+ youtube_session.mount(
290
+ 'http://',
291
+ youtube_adapter
292
+ )
293
+
294
+
295
+ ytt_api = YouTubeTranscriptApi(
296
+ http_client=youtube_session
297
+ )
298
+
299
+
300
+ def fetch_transcript_text(video_id):
301
+ try:
302
+
303
+ print(
304
+ 'FETCHING YOUTUBE TRANSCRIPT:',
305
+ repr(video_id)
306
  )
307
 
308
+ transcript = ytt_api.fetch(
309
+ video_id,
310
+ languages=['en', 'ar']
311
+ )
312
+
313
+ if hasattr(
314
+ transcript,
315
+ 'snippets'
316
+ ):
317
+
318
+ return ' '.join(
319
+ snippet.text
320
+ for snippet in transcript.snippets
321
+ )
322
+
323
  return ' '.join(
324
+ snippet.text
325
+ for snippet in transcript
326
  )
327
 
328
+ except (
329
+ NoTranscriptFound,
330
+ TranscriptsDisabled,
331
+ VideoUnavailable
332
+ ):
333
 
334
+ raise
 
 
 
335
 
336
+ except Exception as e:
 
 
 
337
 
338
+ print(
339
+ 'YOUTUBE FETCH ERROR:',
340
+ repr(e)
341
+ )
342
 
343
+ raise
344
+
345
+
346
+ def process_youtube_video(url):
347
  video_id = extract_youtube_video_id(url)
348
 
349
  if not video_id:
350
+
351
  return (
352
  'Invalid YouTube video URL. '
353
  'Please provide a valid YouTube video link.'
 
358
  repr(video_id)
359
  )
360
 
361
+ try:
 
362
 
363
+ transcript = fetch_transcript_text(
364
+ video_id
365
+ )
 
 
 
 
 
366
 
367
+ if transcript:
 
 
 
368
 
369
+ return transcript
 
 
 
 
370
 
371
+ return (
372
+ 'The YouTube transcript was retrieved '
373
+ 'but contains no readable text.'
374
+ )
375
 
376
+ except NoTranscriptFound:
377
 
378
+ return (
379
+ 'No English or Arabic transcript '
380
+ 'was found for this YouTube video.'
381
+ )
382
 
383
+ except TranscriptsDisabled:
 
 
384
 
385
+ return (
386
+ 'Transcripts are disabled for this '
387
+ 'YouTube video.'
388
  )
389
 
390
+ except VideoUnavailable:
 
 
 
391
 
392
+ return (
393
+ 'The YouTube video is unavailable.'
394
+ )
395
+
396
+ except Exception as e:
397
+
398
+ print(
399
+ 'YOUTUBE TRANSCRIPT ERROR:',
400
+ repr(e)
401
+ )
402
+
403
+ return (
404
+ 'Unable to retrieve the YouTube transcript '
405
+ 'because the server could not establish a '
406
+ 'successful connection with YouTube.\n\n'
407
+ f'Error: {str(e)}'
408
+ )
409
 
410
 
411
  def read_web_page(url):
412
+
413
  try:
414
+
415
+ url = str(url).strip()
416
 
417
  response = requests.get(
418
  url,
 
430
  )
431
 
432
  if response.status_code >= 400:
433
+
434
  return (
435
  'Unable to access webpage. '
436
  f'HTTP status: {response.status_code}'
 
443
  )
444
 
445
  if 'text/plain' in content_type:
446
+
447
  return response.text
448
 
449
  src = response.text
 
459
  'noscript',
460
  'svg'
461
  ]):
462
+
463
  element.decompose()
464
 
465
  text_data = soup.get_text(
 
473
  )
474
 
475
  if not text_data:
476
+
477
  return (
478
+ 'The webpage was accessed successfully '
479
+ 'but contains no readable text.'
 
480
  )
481
 
482
  return text_data
483
 
484
  except requests.exceptions.Timeout:
485
+
486
  return (
487
  'The webpage request timed out. '
488
  'Please try another link.'
489
  )
490
 
491
  except requests.exceptions.RequestException as e:
492
+
493
+ return f'Unable to access webpage: {e}'
 
494
 
495
  except Exception as e:
496
+
497
  return (
498
  'An error occurred while reading '
499
  f'the webpage: {e}'
 
504
  file_path_or_url,
505
  languages=['en', 'ar']
506
  ):
507
+
508
  if not file_path_or_url:
509
+
510
  return 'Unsupported type or format.'
511
 
512
  file_path_or_url = str(
 
516
  if is_youtube_url(
517
  file_path_or_url
518
  ):
519
+
520
  return process_youtube_video(
521
+ file_path_or_url
 
522
  )
523
 
524
  if file_path_or_url.startswith(
525
  ('http://', 'https://')
526
  ):
527
+
528
  return read_web_page(
529
  file_path_or_url
530
  )
 
534
  )
535
 
536
  if lower_path.endswith('.csv'):
537
+
538
  return read_csv(
539
  file_path_or_url
540
  )
541
 
542
  elif lower_path.endswith('.txt'):
543
+
544
  return read_text(
545
  file_path_or_url
546
  )
547
 
548
  elif lower_path.endswith('.pdf'):
549
+
550
  return read_pdf(
551
  file_path_or_url
552
  )
553
 
554
  elif lower_path.endswith('.docx'):
555
+
556
  return read_docx(
557
  file_path_or_url
558
  )
559
 
560
  elif lower_path.endswith('.pptx'):
561
+
562
  return read_pptx(
563
  file_path_or_url
564
  )
565
 
566
  elif lower_path.endswith('.xlsx'):
567
+
568
  return read_xlsx(
569
  file_path_or_url
570
  )
571
 
572
  elif lower_path.endswith('.json'):
573
+
574
  return read_json(
575
  file_path_or_url
576
  )
577
 
578
  elif lower_path.endswith('.html'):
579
+
580
  return read_html(
581
  file_path_or_url
582
  )
583
 
584
  elif lower_path.endswith('.xml'):
585
+
586
  return read_xml(
587
  file_path_or_url
588
  )
 
591
 
592
 
593
  def normalize_text(text):
594
+
595
+ if not isinstance(
596
+ text,
597
+ str
598
+ ):
599
+
600
  text = str(text)
601
 
602
  text = re.sub(
603
+ r'\\n',
604
+ ' ',
605
+ text
606
+ )
607
+
608
+ text = re.sub(
609
+ r'\\',
610
  '',
611
  text
612
  )
 
619
  )
620
 
621
  for punc in punctuation:
622
+
623
  text = text.replace(
624
  punc,
625
  ''
 
631
  text
632
  )
633
 
634
+ words = word_tokenize(
635
+ text
636
+ )
637
 
638
  return ' '.join(words)
639
 
 
649
  do_sample=True,
650
  )
651
 
652
+
653
  chat_model = ChatHuggingFace(
654
  llm=llm
655
  )
656
 
657
+
658
  model_name = (
659
  'sentence-transformers/all-mpnet-base-v2'
660
  )
661
 
662
+
663
  embedding_llm = HuggingFaceEmbeddings(
664
  model_name=model_name
665
  )
666
 
667
+
668
  db = FAISS.load_local(
669
  'faiss_index',
670
  embedding_llm,
 
672
  )
673
 
674
 
675
+ def print_like_dislike(
676
+ x: gr.LikeData
677
+ ):
678
+
679
  print(
680
  x.index,
681
  x.value,
 
687
  user_message,
688
  history
689
  ):
690
+
691
  if not len(user_message):
692
+
693
  raise gr.Error(
694
  'Chat messages cannot be empty'
695
  )
 
707
  history,
708
  link
709
  ):
710
+
711
+ if (
712
+ not len(user_message)
713
+ or not len(link)
714
+ ):
715
+
716
  raise gr.Error(
717
  'Chat messages or links cannot be empty'
718
  )
719
 
720
+ link = str(link).strip()
721
  user_message = str(
722
  user_message
723
  ).strip()
724
 
725
+ combined_message = (
726
+ f'URL: {link}\n'
727
+ f'QUESTION: {user_message}'
728
+ )
729
 
730
  history.append({
731
  'role': 'user',
732
+ 'content': combined_message
733
  })
734
 
735
  return '', history, link
 
740
  history,
741
  file_path
742
  ):
743
+
744
+ if (
745
+ not len(user_message)
746
+ or not file_path
747
+ ):
748
+
749
  raise gr.Error(
750
  'Chat messages or files cannot be empty'
751
  )
752
 
753
  combined_message = (
754
+ f'{file_path}\n'
755
+ f'{user_message}'
756
  )
757
 
758
  history.append({
 
783
  history,
784
  messages1
785
  ):
786
+
787
  user_msg_text = history[-1]['content']
788
 
789
  message = HumanMessage(
 
794
  messages1[-1],
795
  HumanMessage
796
  ):
797
+
798
  messages1 = messages1[:-2]
799
 
800
+ messages1.append(
801
+ message
802
+ )
803
 
804
  if len(messages1) >= 8:
805
+
806
  messages1 = messages1[-8:]
807
 
808
  try:
809
+
810
  response = chat_model.invoke(
811
  messages1
812
  )
813
 
814
  except Exception as e:
815
+
816
  error_message = str(e)
817
 
818
  print(
 
820
  repr(e)
821
  )
822
 
823
+ start_index = (
824
+ error_message.find(
825
+ 'Input validation error:'
826
+ )
827
  )
828
 
829
+ end_index = (
830
+ error_message.find(
831
+ 'and 4096 `max_new_tokens`'
832
+ )
833
  )
834
 
835
  if (
836
  start_index != -1
837
  and end_index != -1
838
  ):
839
+
840
  raise gr.Error(
841
  error_message[
842
  start_index:end_index
 
859
  })
860
 
861
  for character in response.content:
862
+
863
  history[-1]['content'] += character
864
 
865
+ time.sleep(
866
+ 0.0025
867
+ )
868
 
869
  yield history, messages1
870
 
 
873
  history,
874
  messages2
875
  ):
876
+
877
  message = str(
878
  history[-1]['content']
879
  )
 
882
  messages2[-1],
883
  HumanMessage
884
  ):
885
+
886
  messages2 = messages2[:-2]
887
 
888
  similar_docs = db.similarity_search(
 
891
  )
892
 
893
  if similar_docs:
894
+
895
  source_knowledge = '\n'.join(
896
+ [
897
+ x.page_content
898
+ for x in similar_docs
899
+ ]
900
  )
901
+
902
  else:
903
+
904
  source_knowledge = ''
905
 
906
  augmented_prompt = f"""
 
925
  content=augmented_prompt
926
  )
927
 
928
+ messages2.append(
929
+ msg
930
+ )
931
 
932
  if len(messages2) >= 4:
933
+
934
  messages2 = messages2[-4:]
935
 
936
  try:
937
+
938
  response = chat_model.invoke(
939
  messages2
940
  )
941
 
942
  except Exception as e:
943
+
944
  error_message = str(e)
945
 
946
  print(
 
948
  repr(e)
949
  )
950
 
951
+ start_index = (
952
+ error_message.find(
953
+ 'Input validation error:'
954
+ )
955
  )
956
 
957
+ end_index = (
958
+ error_message.find(
959
+ 'and 4096 `max_new_tokens`'
960
+ )
961
  )
962
 
963
  if (
964
  start_index != -1
965
  and end_index != -1
966
  ):
967
+
968
  raise gr.Error(
969
  error_message[
970
  start_index:end_index
 
987
  })
988
 
989
  for character in response.content:
990
+
991
  history[-1]['content'] += character
992
 
993
+ time.sleep(
994
+ 0.0025
995
+ )
996
 
997
  yield history, messages2
998
 
 
1000
  def generate_chart_config(
1001
  description
1002
  ):
1003
+
1004
  system_instructions = """
1005
  You are a Chart.js configuration generator.
1006
 
 
1092
  start = raw.find('{')
1093
  end = raw.rfind('}')
1094
 
1095
+ if (
1096
+ start == -1
1097
+ or end == -1
1098
+ ):
1099
+
1100
  raise ValueError(
1101
  'Model did not return a JSON object.\n'
1102
  f'Raw response:\n{raw}'
 
1111
  raw
1112
  )
1113
 
1114
+ config = json.loads(
1115
+ raw
1116
+ )
1117
 
1118
  if 'type' not in config:
1119
+
1120
  raise ValueError(
1121
  "Chart config missing 'type'"
1122
  )
1123
 
1124
  if 'data' not in config:
1125
+
1126
  raise ValueError(
1127
  "Chart config missing 'data'"
1128
  )
1129
 
1130
  if 'labels' not in config['data']:
1131
+
1132
  raise ValueError(
1133
  "Chart config missing 'data.labels'"
1134
  )
1135
 
1136
  if 'datasets' not in config['data']:
1137
+
1138
  raise ValueError(
1139
  "Chart config missing 'data.datasets'"
1140
  )
 
1143
  config['data']['datasets'],
1144
  list
1145
  ):
1146
+
1147
  raise ValueError(
1148
  "'data.datasets' must be a list"
1149
  )
 
1155
  history,
1156
  messages3
1157
  ):
1158
+
1159
  message = str(
1160
  history[-1]['content']
1161
  )
 
1164
  messages3[-1],
1165
  HumanMessage
1166
  ):
1167
+
1168
  messages3 = messages3[:-2]
1169
 
1170
  if '#chart' in message.lower():
 
1177
  )[1].strip()
1178
 
1179
  if not chart_description:
1180
+
1181
  combined_content = (
1182
  'Please provide chart details after #chart.'
1183
  )
1184
 
1185
  else:
1186
+
1187
  chart_config = None
1188
 
1189
  try:
1190
+
1191
  chart_config = (
1192
  generate_chart_config(
1193
  chart_description
 
1203
  )
1204
 
1205
  except Exception as e:
1206
+
1207
  print(
1208
  'CHART GENERATION ERROR:',
1209
  repr(e)
 
1214
  f'Error: {str(e)}'
1215
  )
1216
 
 
 
1217
  if chart_config:
1218
+
1219
  try:
1220
+
1221
  config_json = json.dumps(
1222
  chart_config,
1223
  separators=(',', ':')
 
1251
  chart_response.status_code
1252
  )
1253
 
1254
+ if (
1255
+ chart_response.status_code
1256
+ != 200
1257
+ ):
1258
+
1259
  print(
1260
  'QUICKCHART RESPONSE:',
1261
  chart_response.text[:1000]
1262
  )
1263
 
1264
  combined_content = (
1265
+ 'QuickChart failed to generate '
1266
+ 'the chart.\n\n'
1267
  f'HTTP Status: '
1268
  f'{chart_response.status_code}'
1269
  )
1270
 
1271
  else:
1272
+
1273
  image_html = (
1274
  f'<img src="{chart_url}" '
1275
  'alt="Generated Chart" '
 
1280
  )
1281
 
1282
  chart_summary_prompt = (
1283
+ 'The following Chart.js configuration '
1284
+ 'was generated:\n\n'
1285
  f'{json.dumps(chart_config, indent=2)}\n\n'
1286
  'Briefly describe what this chart '
1287
  'represents.'
 
1301
  ]
1302
 
1303
  try:
1304
+
1305
  response = (
1306
  chat_model.invoke(
1307
  analysis_messages
 
1313
  )
1314
 
1315
  except Exception as e:
1316
+
1317
  print(
1318
  'CHART ANALYSIS ERROR:',
1319
  repr(e)
 
1329
  )
1330
 
1331
  except Exception as e:
1332
+
1333
  print(
1334
  'QUICKCHART REQUEST ERROR:',
1335
  repr(e)
 
1342
  )
1343
 
1344
  else:
1345
+
1346
  prompt = HumanMessage(
1347
  content=message
1348
  )
1349
 
1350
+ messages3.append(
1351
+ prompt
1352
+ )
1353
 
1354
  if len(messages3) >= 6:
1355
+
1356
  messages3 = messages3[-6:]
1357
 
1358
  try:
1359
+
1360
  response = chat_model.invoke(
1361
  messages3
1362
  )
1363
 
1364
  except Exception as e:
1365
+
1366
  error_message = str(e)
1367
 
1368
  print(
 
1370
  repr(e)
1371
  )
1372
 
1373
+ start_index = (
1374
+ error_message.find(
1375
+ 'Input validation error:'
1376
+ )
1377
  )
1378
 
1379
+ end_index = (
1380
+ error_message.find(
1381
+ 'and 4096 `max_new_tokens`'
1382
+ )
1383
  )
1384
 
1385
  if (
1386
  start_index != -1
1387
  and end_index != -1
1388
  ):
1389
+
1390
  raise gr.Error(
1391
  error_message[
1392
  start_index:end_index
 
1403
  )
1404
  )
1405
 
1406
+ combined_content = (
1407
+ response.content
1408
+ )
1409
 
1410
  history.append({
1411
  'role': 'assistant',
 
1413
  })
1414
 
1415
  for character in combined_content:
1416
+
1417
  history[-1]['content'] += character
1418
 
1419
+ time.sleep(
1420
+ 0.0025
1421
+ )
1422
 
1423
  yield history, messages3
1424
 
1425
 
1426
  def extract_url_from_text(text):
1427
+
1428
  if not text:
1429
+
1430
  return None
1431
 
1432
+ if isinstance(
1433
+ text,
1434
+ list
1435
+ ):
1436
+
1437
+ parts = []
1438
 
1439
+ for item in text:
1440
+
1441
+ if isinstance(
1442
+ item,
1443
+ dict
1444
+ ):
1445
+
1446
+ value = item.get(
1447
+ 'text',
1448
+ ''
1449
+ )
1450
+
1451
+ parts.append(
1452
+ str(value)
1453
+ )
1454
+
1455
+ else:
1456
+
1457
+ parts.append(
1458
+ str(item)
1459
+ )
1460
+
1461
+ text = ' '.join(parts)
1462
+
1463
+ elif isinstance(
1464
+ text,
1465
+ dict
1466
+ ):
1467
+
1468
+ text = str(
1469
+ text.get(
1470
+ 'text',
1471
+ ''
1472
+ )
1473
+ )
1474
+
1475
+ else:
1476
+
1477
+ text = str(text)
1478
 
1479
  text = text.replace(
1480
+ '\\n',
1481
+ ' '
1482
  )
1483
 
1484
  text = text.replace(
 
1486
  ''
1487
  )
1488
 
1489
+ markdown_matches = re.findall(
1490
+ r'\]\(\s*(https?://[^)\s]+)',
1491
+ text,
1492
+ flags=re.IGNORECASE
1493
  )
1494
 
1495
+ if markdown_matches:
1496
+
1497
+ return markdown_matches[0].rstrip(
1498
+ '.,!?;:)]}'
 
1499
  )
1500
 
1501
+ url_matches = re.findall(
1502
  r'https?://[^\s<>"\']+',
1503
+ text,
1504
+ flags=re.IGNORECASE
1505
  )
1506
 
1507
+ if url_matches:
1508
+
1509
+ url = url_matches[0]
1510
+
1511
+ return url.rstrip(
1512
+ '.,!?;:)]}'
1513
  )
1514
 
1515
  return None
1516
 
1517
 
1518
+ def extract_user_query_from_link_message(
1519
+ content,
1520
+ link
1521
+ ):
1522
+
1523
+ if isinstance(
1524
+ content,
1525
+ list
1526
+ ):
1527
+
1528
+ parts = []
1529
+
1530
+ for item in content:
1531
+
1532
+ if isinstance(
1533
+ item,
1534
+ dict
1535
+ ):
1536
+
1537
+ parts.append(
1538
+ str(
1539
+ item.get(
1540
+ 'text',
1541
+ ''
1542
+ )
1543
+ )
1544
+ )
1545
+
1546
+ else:
1547
+
1548
+ parts.append(
1549
+ str(item)
1550
+ )
1551
+
1552
+ content = ' '.join(parts)
1553
+
1554
+ elif isinstance(
1555
+ content,
1556
+ dict
1557
+ ):
1558
+
1559
+ content = str(
1560
+ content.get(
1561
+ 'text',
1562
+ ''
1563
+ )
1564
+ )
1565
+
1566
+ else:
1567
+
1568
+ content = str(content)
1569
+
1570
+ content = content.replace(
1571
+ '\\n',
1572
+ '\n'
1573
+ )
1574
+
1575
+ content = content.replace(
1576
+ '\\',
1577
+ ''
1578
+ )
1579
+
1580
+ content = content.strip()
1581
+
1582
+ question_match = re.search(
1583
+ r'QUESTION\s*:\s*(.*)$',
1584
+ content,
1585
+ flags=re.IGNORECASE | re.DOTALL
1586
+ )
1587
+
1588
+ if question_match:
1589
+
1590
+ return question_match.group(
1591
+ 1
1592
+ ).strip()
1593
+
1594
+ if link:
1595
+
1596
+ question = content.replace(
1597
+ link,
1598
+ ''
1599
+ )
1600
+
1601
+ question = re.sub(
1602
+ r'URL\s*:\s*',
1603
+ '',
1604
+ question,
1605
+ flags=re.IGNORECASE
1606
+ )
1607
+
1608
+ return question.strip()
1609
+
1610
+ return content
1611
+
1612
+
1613
  def Link_Scratch(
1614
  history,
1615
+ messages4
 
1616
  ):
 
 
 
1617
 
1618
+ combined_message = (
1619
+ history[-1]['content']
1620
+ )
1621
 
1622
  if isinstance(
1623
  messages4[-1],
1624
  HumanMessage
1625
  ):
1626
+
1627
  messages4 = messages4[:-2]
1628
 
1629
+ link = extract_url_from_text(
1630
+ combined_message
1631
+ )
1632
+
1633
+ user_message = (
1634
+ extract_user_query_from_link_message(
1635
+ combined_message,
1636
+ link
1637
+ )
1638
+ )
1639
+
1640
  print(
1641
+ 'RAW LINK REQUEST:',
1642
+ repr(combined_message)
1643
  )
1644
 
1645
  print(
 
1647
  repr(link)
1648
  )
1649
 
1650
+ print(
1651
+ 'USER QUERY:',
1652
+ repr(user_message)
1653
+ )
1654
+
1655
  if not link:
1656
+
1657
  response_message = (
1658
+ 'Please provide a valid URL '
1659
+ 'starting with http:// or https://'
1660
  )
1661
 
1662
  else:
1663
+
1664
+ result = read_data(
1665
+ link
1666
+ )
1667
 
1668
  print(
1669
  'LINK READ RESULT TYPE:',
 
1684
  ]
1685
 
1686
  if (
1687
+ isinstance(
1688
+ result,
1689
+ str
1690
+ )
1691
  and (
1692
  result in error_results
1693
  or result.startswith(
 
1696
  or result.startswith(
1697
  'An error occurred while reading'
1698
  )
1699
+ or result.startswith(
1700
+ 'Unable to retrieve the YouTube transcript'
1701
+ )
1702
+ or result.startswith(
1703
+ 'No English or Arabic transcript'
1704
+ )
1705
+ or result.startswith(
1706
+ 'Transcripts are disabled'
1707
+ )
1708
+ or result.startswith(
1709
+ 'The YouTube video is unavailable'
1710
+ )
1711
  )
1712
  ):
1713
+
1714
  response_message = result
1715
 
1716
  else:
1717
+
1718
  content_data = normalize_text(
1719
  result
1720
  )
1721
 
1722
  if not content_data:
1723
+
1724
  response_message = (
1725
  'The provided link is empty or '
1726
  'does not contain any meaningful words.'
1727
  )
1728
 
1729
  else:
1730
+
1731
  augmented_prompt = f"""
1732
  You are an AI designed to help understand
1733
  and extract information from provided Link Content.
 
1740
  Link Content:
1741
  {content_data}
1742
 
1743
+ Answer the user's query using the Link Content.
1744
+ Do not treat the URL itself or the word "what"
1745
+ as part of the URL.
1746
  """
1747
 
1748
  message = HumanMessage(
 
1756
  messages4 = messages4[-1:]
1757
 
1758
  try:
1759
+
1760
+ response = chat_model.invoke(
1761
+ messages4
 
1762
  )
1763
 
1764
  except Exception as e:
1765
+
1766
  error_message = str(e)
1767
 
1768
  print(
 
1786
  start_index != -1
1787
  and end_index != -1
1788
  ):
1789
+
1790
  raise gr.Error(
1791
  error_message[
1792
  start_index:end_index
 
1813
  })
1814
 
1815
  for character in response_message:
1816
+
1817
  history[-1]['content'] += character
1818
 
1819
+ time.sleep(
1820
+ 0.0025
1821
+ )
1822
 
1823
  yield history, messages4
1824
 
 
1827
  text,
1828
  every=8
1829
  ):
1830
+
1831
  return '\n'.join(
1832
  text[i:i + every]
1833
  for i in range(
 
1838
  )
1839
 
1840
 
1841
+ def display_file_name(
1842
+ file
1843
+ ):
1844
+
1845
  supported_extensions = [
1846
  '.csv',
1847
  '.txt',
 
1862
  file_extension.lower()
1863
  in supported_extensions
1864
  ):
1865
+
1866
  file_name = os.path.basename(
1867
  file.name
1868
  )
 
1904
  filepath,
1905
  messages5
1906
  ):
1907
+
1908
  combined_message = str(
1909
  history[-1]['content']
1910
  )
 
1913
  messages5[-1],
1914
  HumanMessage
1915
  ):
1916
+
1917
  messages5 = messages5[:-2]
1918
 
1919
  link = ''
1920
  user_message = ''
1921
 
1922
  if '\n' in combined_message:
1923
+
1924
  link, user_message = (
1925
  combined_message.split(
1926
  '\n',
 
1928
  )
1929
  )
1930
 
1931
+ user_message = (
1932
+ user_message.strip()
1933
+ )
1934
 
1935
  result = read_data(
1936
  filepath
1937
  )
1938
 
1939
  if result == 'Unsupported type or format.':
1940
+
1941
  response_message = result
1942
 
1943
  else:
1944
+
1945
  content_data = normalize_text(
1946
  result
1947
  )
1948
 
1949
  if not content_data:
1950
+
1951
  response_message = (
1952
  'The file is empty or does not '
1953
  'contain any meaningful words.'
1954
  )
1955
 
1956
  else:
1957
+
1958
  augmented_prompt = f"""
1959
  You are an AI designed to help understand
1960
  and extract information from provided File Content.
 
1984
  messages5 = messages5[-1:]
1985
 
1986
  try:
1987
+
1988
  response = (
1989
  chat_model.invoke(
1990
  messages5
 
1992
  )
1993
 
1994
  except Exception as e:
1995
+
1996
  error_message = str(e)
1997
 
1998
  print(
 
2016
  start_index != -1
2017
  and end_index != -1
2018
  ):
2019
+
2020
  raise gr.Error(
2021
  error_message[
2022
  start_index:end_index
 
2043
  })
2044
 
2045
  for character in response_message:
2046
+
2047
  history[-1]['content'] += character
2048
 
2049
+ time.sleep(
2050
+ 0.0025
2051
+ )
2052
 
2053
  yield history, messages5
2054
 
 
2057
  history,
2058
  messages6
2059
  ):
2060
+
2061
  message = history[-1]['content']
2062
 
2063
  if isinstance(
2064
  messages6[-1],
2065
  HumanMessage
2066
  ):
2067
+
2068
  messages6 = messages6[:-2]
2069
 
2070
  links = [
 
2072
  ]
2073
 
2074
  result = '\n'.join(
2075
+ [
2076
+ read_data(link)
2077
+ for link in links
2078
+ ]
2079
  )
2080
 
2081
  content_data = normalize_text(
 
2104
  content=augmented_prompt
2105
  )
2106
 
2107
+ messages6.append(
2108
+ msg
2109
+ )
2110
 
2111
  if len(messages6) >= 4:
2112
+
2113
  messages6 = messages6[-4:]
2114
 
2115
  try:
2116
+
2117
  response = chat_model.invoke(
2118
  messages6
2119
  )
2120
 
2121
  except Exception as e:
2122
+
2123
  error_message = str(e)
2124
 
2125
  print(
 
2127
  repr(e)
2128
  )
2129
 
2130
+ start_index = (
2131
+ error_message.find(
2132
+ 'Input validation error:'
2133
+ )
2134
  )
2135
 
2136
+ end_index = (
2137
+ error_message.find(
2138
+ 'and 4096 `max_new_tokens`'
2139
+ )
2140
  )
2141
 
2142
  if (
2143
  start_index != -1
2144
  and end_index != -1
2145
  ):
2146
+
2147
  raise gr.Error(
2148
  error_message[
2149
  start_index:end_index
 
2166
  })
2167
 
2168
  for character in response.content:
2169
+
2170
  history[-1]['content'] += character
2171
 
2172
+ time.sleep(
2173
+ 0.0025
2174
+ )
2175
 
2176
  yield history, messages6
2177
 
 
2465
  queue=True
2466
  ).then(
2467
  Link_Scratch,
2468
+ [chatbot, messages4],
2469
  [chatbot, messages4]
2470
  )
2471
 
 
2476
  queue=True
2477
  ).then(
2478
  Link_Scratch,
2479
+ [chatbot, messages4],
2480
  [chatbot, messages4]
2481
  )
2482
 
 
2487
  queue=True
2488
  ).then(
2489
  Link_Scratch,
2490
+ [chatbot, messages4],
2491
  [chatbot, messages4]
2492
  )
2493