1
+ # Standard library imports
2
+ import base64
3
+ import json
1
4
import os
5
+ import random
2
6
import re
3
- import json
4
- import base64
5
7
import string
6
- import random
7
- import requests
8
- from typing import Optional
8
+ import uuid
9
9
10
- from bardapi .models .result import BardResult
10
+ # Third-party imports
11
+ from langdetect import detect
12
+ from typing import Optional
11
13
12
14
try :
13
15
from deep_translator import GoogleTranslator
14
16
from google .cloud import translate_v2 as translate
15
17
except ImportError :
16
18
pass
17
19
20
+ # Local module or custom library imports
18
21
from bardapi .constants import (
19
22
ALLOWED_LANGUAGES ,
20
- SESSION_HEADERS ,
21
23
REPLIT_SUPPORT_PROGRAM_LANGUAGES ,
24
+ SESSION_HEADERS ,
22
25
TEXT_GENERATION_WEB_SERVER_PARAM ,
23
26
Tool ,
24
27
)
28
+ from bardapi .models .result import BardResult
25
29
from bardapi .utils import (
26
- build_input_replit_data_struct ,
27
- build_export_data_structure ,
28
30
build_bard_answer ,
29
- upload_image ,
30
- extract_bard_cookie ,
31
+ build_export_data_structure ,
32
+ build_input_replit_data_struct ,
31
33
build_input_text_struct ,
34
+ extract_bard_cookie ,
35
+ upload_image ,
32
36
)
33
37
34
38
@@ -519,7 +523,7 @@ def export_conversation(self, bard_answer, title: str = "") -> dict:
519
523
return {"url" : url , "status_code" : resp .status_code }
520
524
521
525
def ask_about_image (
522
- self , input_text : str , image : bytes , image_name : str , lang : Optional [str ] = None
526
+ self , input_text : str , image : bytes , lang : Optional [str ] = None
523
527
) -> dict :
524
528
"""
525
529
Send Bard image along with question and get answer
@@ -528,12 +532,11 @@ def ask_about_image(
528
532
>>> token = 'xxxxxx'
529
533
>>> bard = Bard(token=token)
530
534
>>> image = open('image.jpg', 'rb').read()
531
- >>> bard_answer = bard.ask_about_image("what is in the image?", image, 'image.jpg' )['content']
535
+ >>> bard_answer = bard.ask_about_image("what is in the image?", image)['content']
532
536
533
537
Args:
534
538
input_text (str): Input text for the query.
535
539
image (bytes): Input image bytes for the query, support image types: jpeg, png, webp
536
- image_name (str): Short file name
537
540
lang (str, optional): Language to use.
538
541
539
542
Returns:
@@ -552,7 +555,142 @@ def ask_about_image(
552
555
"status_code": int
553
556
}
554
557
"""
555
- return self .get_answer (input_text , image , image_name )
558
+ if self .google_translator_api_key is not None :
559
+ google_official_translator = translate .Client (
560
+ api_key = self .google_translator_api_key
561
+ )
562
+ else :
563
+ translator_to_eng = GoogleTranslator (source = "auto" , target = "en" )
564
+
565
+ # [Optional] Set language
566
+ if (
567
+ (self .language is not None or lang is not None )
568
+ and self .language not in ALLOWED_LANGUAGES
569
+ and self .google_translator_api_key is None
570
+ ):
571
+ translator_to_eng = GoogleTranslator (source = "auto" , target = "en" )
572
+ transl_text = translator_to_eng .translate (input_text )
573
+ elif (
574
+ (self .language is not None or lang is not None )
575
+ and self .language not in ALLOWED_LANGUAGES
576
+ and self .google_translator_api_key is not None
577
+ ):
578
+ transl_text = google_official_translator .translate (
579
+ input_text , target_language = "en"
580
+ )
581
+ elif (
582
+ (self .language is None or lang is None )
583
+ and self .language not in ALLOWED_LANGUAGES
584
+ and self .google_translator_api_key is None
585
+ ):
586
+ translator_to_eng = GoogleTranslator (source = "auto" , target = "en" )
587
+ transl_text = translator_to_eng .translate (input_text )
588
+
589
+ # Supported format: jpeg, png, webp
590
+ image_url = upload_image (image )
591
+
592
+ input_data_struct = [
593
+ None ,
594
+ [
595
+ [transl_text , 0 , None , [[[image_url , 1 ], "uploaded_photo.jpg" ]]],
596
+ [lang if lang is not None else self .language ],
597
+ ["" , "" , "" ],
598
+ "" , # Unknown random string value (1000 characters +)
599
+ uuid .uuid4 ().hex , # Should be random uuidv4 (32 characters)
600
+ None ,
601
+ [1 ],
602
+ 0 ,
603
+ [],
604
+ [],
605
+ ],
606
+ ]
607
+ params = {
608
+ "bl" : "boq_assistant-bard-web-server_20230716.16_p2" ,
609
+ "_reqid" : str (self ._reqid ),
610
+ "rt" : "c" ,
611
+ }
612
+ input_data_struct [1 ] = json .dumps (input_data_struct [1 ])
613
+ data = {
614
+ "f.req" : json .dumps (input_data_struct ),
615
+ "at" : self .SNlM0e ,
616
+ }
617
+
618
+ resp = self .session .post (
619
+ "https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate" ,
620
+ params = params ,
621
+ data = data ,
622
+ timeout = self .timeout ,
623
+ proxies = self .proxies ,
624
+ )
625
+
626
+ # Post-processing of response
627
+ resp_dict = json .loads (resp .content .splitlines ()[3 ])[0 ][2 ]
628
+ if not resp_dict :
629
+ return {
630
+ "content" : f"Response Error: { resp .content } . "
631
+ f"\n Unable to get response."
632
+ f"\n Please double-check the cookie values and verify your network environment or google account."
633
+ }
634
+ parsed_answer = json .loads (resp_dict )
635
+ content = parsed_answer [4 ][0 ][1 ][0 ]
636
+ try :
637
+ if self .language is not None and self .google_translator_api_key is None :
638
+ translator = GoogleTranslator (source = "en" , target = self .language )
639
+ translated_content = translator .translate (content )
640
+
641
+ elif lang is not None and self .google_translator_api_key is None :
642
+ translator = GoogleTranslator (source = "en" , target = lang )
643
+ translated_content = translator .translate (content )
644
+
645
+ elif (
646
+ lang is None and self .language is None
647
+ ) and self .google_translator_api_key is None :
648
+ us_lang = detect (input_text )
649
+ translator = GoogleTranslator (source = "en" , target = us_lang )
650
+ translated_content = translator .translate (content )
651
+
652
+ elif (
653
+ self .language is not None and self .google_translator_api_key is not None
654
+ ):
655
+ translated_content = google_official_translator .translate (
656
+ content , target_language = self .language
657
+ )
658
+ elif lang is not None and self .google_translator_api_key is not None :
659
+ translated_content = google_official_translator .translate (
660
+ content , target_language = lang
661
+ )
662
+ elif (
663
+ self .language is None and lang is None
664
+ ) and self .google_translator_api_key is not None :
665
+ us_lang = detect (input_text )
666
+ translated_content = google_official_translator .translate (
667
+ content , target_language = us_lang
668
+ )
669
+ except Exception as e :
670
+ print (f"Translation failed, and the original text has been returned. \n { e } " )
671
+ translated_content = content
672
+
673
+ # Returned dictionary object
674
+ bard_answer = {
675
+ "content" : translated_content ,
676
+ "conversation_id" : parsed_answer [1 ][0 ],
677
+ "response_id" : parsed_answer [1 ][1 ],
678
+ "factuality_queries" : parsed_answer [3 ],
679
+ "text_query" : parsed_answer [2 ][0 ] if parsed_answer [2 ] else "" ,
680
+ "choices" : [{"id" : x [0 ], "content" : x [1 ]} for x in parsed_answer [4 ]],
681
+ "links" : self ._extract_links (parsed_answer [4 ]),
682
+ "images" : ["" ],
683
+ "program_lang" : "" ,
684
+ "code" : "" ,
685
+ "status_code" : resp .status_code ,
686
+ }
687
+ self .conversation_id , self .response_id , self .choice_id = (
688
+ bard_answer ["conversation_id" ],
689
+ bard_answer ["response_id" ],
690
+ bard_answer ["choices" ][0 ]["id" ],
691
+ )
692
+ self ._reqid += 100000
693
+ return bard_answer
556
694
557
695
def export_replit (
558
696
self ,
@@ -629,3 +767,26 @@ def export_replit(
629
767
self ._reqid += 100000
630
768
631
769
return {"url" : url , "status_code" : resp .status_code }
770
+
771
+ def _extract_links (self , data : list ) -> list :
772
+ """
773
+ Extract links from the given data.
774
+
775
+ Args:
776
+ data: Data to extract links from.
777
+
778
+ Returns:
779
+ list: Extracted links.
780
+ """
781
+ links = []
782
+ if isinstance (data , list ):
783
+ for item in data :
784
+ if isinstance (item , list ):
785
+ links .extend (self ._extract_links (item ))
786
+ elif (
787
+ isinstance (item , str )
788
+ and item .startswith ("http" )
789
+ and "favicon" not in item
790
+ ):
791
+ links .append (item )
792
+ return links
0 commit comments