1+ # Standard library imports
2+ import base64
3+ import json
14import os
5+ import random
26import re
3- import json
4- import base64
57import string
6- import random
7- import requests
8- from typing import Optional
8+ import uuid
99
10- from bardapi .models .result import BardResult
10+ # Third-party imports
11+ from langdetect import detect
12+ from typing import Optional
1113
1214try :
1315 from deep_translator import GoogleTranslator
1416 from google .cloud import translate_v2 as translate
1517except ImportError :
1618 pass
1719
20+ # Local module or custom library imports
1821from bardapi .constants import (
1922 ALLOWED_LANGUAGES ,
20- SESSION_HEADERS ,
2123 REPLIT_SUPPORT_PROGRAM_LANGUAGES ,
24+ SESSION_HEADERS ,
2225 TEXT_GENERATION_WEB_SERVER_PARAM ,
2326 Tool ,
2427)
28+ from bardapi .models .result import BardResult
2529from bardapi .utils import (
26- build_input_replit_data_struct ,
27- build_export_data_structure ,
2830 build_bard_answer ,
29- upload_image ,
30- extract_bard_cookie ,
31+ build_export_data_structure ,
32+ build_input_replit_data_struct ,
3133 build_input_text_struct ,
34+ extract_bard_cookie ,
35+ upload_image ,
3236)
3337
3438
@@ -519,7 +523,7 @@ def export_conversation(self, bard_answer, title: str = "") -> dict:
519523 return {"url" : url , "status_code" : resp .status_code }
520524
521525 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
523527 ) -> dict :
524528 """
525529 Send Bard image along with question and get answer
@@ -528,12 +532,11 @@ def ask_about_image(
528532 >>> token = 'xxxxxx'
529533 >>> bard = Bard(token=token)
530534 >>> 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']
532536
533537 Args:
534538 input_text (str): Input text for the query.
535539 image (bytes): Input image bytes for the query, support image types: jpeg, png, webp
536- image_name (str): Short file name
537540 lang (str, optional): Language to use.
538541
539542 Returns:
@@ -552,7 +555,142 @@ def ask_about_image(
552555 "status_code": int
553556 }
554557 """
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
556694
557695 def export_replit (
558696 self ,
@@ -629,3 +767,26 @@ def export_replit(
629767 self ._reqid += 100000
630768
631769 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