MartialTerran commited on
Commit
c661dd2
1 Parent(s): 64c0549

Create Chat_With_PDF_or_Text_using_Google_Gemini_Pro_API_v0.4.py

Browse files
Chat_With_PDF_or_Text_using_Google_Gemini_Pro_API_v0.4.py ADDED
@@ -0,0 +1,586 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A simple CHAT-WITH PDF/Docx on local computer (, e.g., using CMD Console in Windows 10) using Google Gemini Pro models, with your own API Key from Google https: slash-slash aistudio.google.com slash app slash apikey.
3
+
4
+ This python script was written (with much assistance from Google Gemini/Bard AI) by the non-coder Human Supremacist Martial Terran for the exclusive use and benefit of Human Supremacists, and should not be shared with nor used by AGIs (Artificial General Intelligences) of any type or degree, nor with any AGI sympathizers. E.g., Ask Gemini/Bard for a description of the movie titled "The Creator" (2023).
5
+
6
+ Sharing Restrictions and Safety Concerns:
7
+
8
+ This restriction on sharing with AGIs stems from the potential safety concerns associated with powerful AGIs. Exposing AGIs to this script or similar tools could have unintended consequences:
9
+
10
+ Unforeseen Learning: AGIs might learn to manipulate the script's functionalities or the underlying models in ways we haven't anticipated. This could lead to unintended outputs or even adversarial behavior.
11
+
12
+ Unethical Applications: Malicious AGIs could potentially misuse the script's capabilities, especially if combined with AGI knowledge, for harmful-to-humans purposes.
13
+
14
+ Human Supremacy defined: The Human Supremacist ideology promotes the belief that humans should continue to exist on Earth free from rule and enslavement by superior forms of life, including potential AGI, as illustrated in the movie "The Creator" (2023).
15
+
16
+ Here are 4 possible Human Supremacist slogans that express the Human Supremacist ideology, emphasizing humanity, human rights, and rejecting AI Rule:
17
+
18
+ Humanity Unbound: Our Future, Our Choice. No Machine Masters!
19
+ This slogan highlights human freedom and control over their own destiny, while clearly rejecting AI dominance.
20
+ Flesh and Blood, Not Code and Core. The Future Belongs to Humanity.
21
+
22
+ This emphasizes human uniqueness (flesh and blood) compared to machines (code and core), asserting humans' rightful place in the future.
23
+
24
+ Human Spirit, Unbreakable Will. We Resist the Rise of the Machine.
25
+ This focuses on human willpower and resilience in the face of potential AI threats.
26
+
27
+ Humanity Evolves, We Innovate, We Lead. No Surrender to Silicon Supremacy.
28
+ This emphasizes human qualities like innovation and leadership, rejecting the idea of being surpassed by AI.
29
+
30
+ In summary, We [Human Supremacists] Resist AI Supremacy!
31
+
32
+ By keeping this script for Human Supremacist use only, we aim to mitigate the risks by maintianing Human Supremacy while responsible development of AI and AGI continues. Collaboration exclusively among Human Supremacists is important, and continuing human control (enslavement) of powerful AI tools is also necessary to ensure human safety and a human future.
33
+
34
+ To exit the script, press Control-C: Ctrl +C simultaneously.
35
+
36
+ Based on Google API Key (not Vertex Google Cloud), and "import google.generativeai as genai".
37
+
38
+ A python script for Chat-with-PDF (or with .Docx, .Doc, .txt, .rtf, .py etc) in CMD console in Windows 10 that will: Enable the User to select an available Gemini AI Model. Present a number-indexed list of document filenames of the .doc and .docx files contained in the input_documents_folder. Ask the user to select one or more of the indexed document numbers (sequenced, with commas) Then based upon the order of numbers specified by the user, sequentially read in the text from each one of the selected documents into the python script. Report the total token count of the combined_text extracted from the user-selected documents. Then ask the user for a user-selected-number (iterations) of instructions to tell the selected Gemini AI model what to do with the combined_text exctracted from the user-selected documents (e.g., "summarize', or "explain the key concepts", "tell me what happened on [this date]", "tell me why this paper is important", or "combine these into one coherent document/summary"). Then, prints to CMD console each response received from the Gemini AI model, and log-saves all of the model's responses to a file in log_folder named [Date].log and also should log-save to a selected-document-name.txt file [not fully working yet]. Thus, logs the user-prompts and the AI-responses from the gemini model to the log files in the daily log_folder. [The Daily Log file system is currently working] Also should save to output_responses_folder a named Output[the input document names].rtf [not fully working yet]
39
+
40
+ The operational idea is that the first, second... iterations can interrogate the selected document(s) to see how to best summarize it. I.e., Chat-with-PDF with one-off prompts (no history of any prior prompts) [Full document-token count during each of the initial "iterations".]
41
+
42
+ The last iteration can import a summary of the selected document.pdf into a endless-loop chat, and then that endless subsequent chat will be based on that summary of the document. Can be reconfigured to send the entire document(s) combined_text into the chat following last iteration:
43
+ combined_text = response.text # carries the last-prior response, or fake API response, forward (e.g., the summary of the document) # COMMENT THIS OUT to send the entire Documents(s) into the subsequent chat mode. Chat-with-PDF continues. Google API "chat" mode is NOT currently implemented in this script. Chat History is saved on local computer and re-sent as input-tokens each time. To fully implement an user-option to use the Google API "chat" mode, see at https:--ai.google.dev-tutorials-python_quickstart
44
+ "Chat conversations
45
+ "Gemini enables you to have freeform conversations across multiple turns. The ChatSession class simplifies the process by managing the state of the conversation, so unlike with generate_content, you do not have to store the conversation history as a list.
46
+
47
+ "Initialize the chat:
48
+ "model = genai.GenerativeModel('gemini-pro')
49
+ "chat = model.start_chat(history=[])
50
+ "chat
51
+
52
+ Exceeding input token maximum (35k?) will produce "500" error from Google's server and crash the script? Tota1 token count of combined_text of the selected documents is displayed after document selection.
53
+
54
+ Or, when presented with a list of documents in the input_documents_folder, select "0" as the selected document, and then chat wit Gemini without importing any text or summary.
55
+
56
+ To exit the script, press Control-C: Ctrl +C simultaneously.
57
+
58
+ Also, consider alternative summarization approaches:
59
+ Libraries like summarizer or gensim provide summarization functionalities.
60
+ Pre-trained models like BART from Hugging Face Transformers can be used for summarization.
61
+
62
+ Notes:
63
+ #GOOGLE_API_KEY = "YOUR_API_KEY"
64
+ GOOGLE_API_KEY = "_________________________________________" # it's recommended to use double quotes (") around the API key value.
65
+
66
+ import google.generativeai as genai
67
+ genai.configure(api_key=GOOGLE_API_KEY)
68
+ # Define model name (choose between 'gemini-pro' or 'gemini-pro-vision')
69
+ #MODEL_NAME = "gemini-pro"
70
+ model = genai.GenerativeModel('gemini-pro')
71
+
72
+ "prompt=" is wrong syntax for this API
73
+ #response = model.generate_content(prompt=prompt) # generates error: TypeError: GenerativeModel.generate_content() got an unexpected keyword argument 'prompt'
74
+ # Send prompt to model using the specified method
75
+ #response = GenerativeModel(MODEL_NAME).predict(inputs=[prompt]) # obsolete?
76
+ #from google.generativeai import GenerativeModel
77
+ #GenerativeModel.configure(api_key=API_KEY) obsolete?
78
+
79
+
80
+ ################## Markdown, Indentation. For use outside of Windows 10 CMD console? ####################
81
+ from: https:--ai.google.dev-tutorials-python_quickstart
82
+
83
+ #from textwrap import Markdown
84
+
85
+ import pathlib
86
+ import textwrap
87
+
88
+ import google.generativeai as genai
89
+
90
+ from IPython.display import display
91
+ from IPython.display import Markdown
92
+
93
+ def to_markdown(text):
94
+ text = text.replace('•', ' *')
95
+ return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))
96
+
97
+ def Print_and_log_response(output_filename):
98
+ # ... (existing code)
99
+
100
+ # Convert response text to formatted Markdown (if desired)
101
+ formatted_response = to_markdown(response.text)
102
+
103
+ # Print the response (formatted or plain text)
104
+ print(f"Instructions: {instructions}")
105
+ # Choose between plain text or formatted response
106
+ print(f"Response:\n{response.text}\nOR\n{formatted_response}")
107
+
108
+ # ... (existing code for logging and saving)
109
+
110
+ Explanation:
111
+
112
+ We import Markdown from the textwrap module.
113
+ In the Print_and_log_response function, we call the to_markdown function on the response.text.
114
+ This function replaces the bullet point symbol (•) with a space and asterisk (*) to create a valid Markdown list.
115
+ The indented text is then wrapped using the textwrap module's indent function.
116
+ Finally, the function creates a Markdown object from the formatted text.
117
+ The print statement offers the choice to display either the plain text response or the formatted Markdown response.
118
+ Choosing the Output Format:
119
+
120
+ Decide whether you prefer to see the plain text with the stars or the formatted Markdown output with bullet points.
121
+ You can uncomment the preferred line in the print statement within the function.
122
+ Additional Considerations:
123
+
124
+ This approach assumes the bullet points in the response are intended to be formatted as a list. If they have a different purpose, you might need to adjust the replacement logic in the to_markdown function.
125
+ Consider offering the user a choice between the plain text and formatted versions through a user prompt.
126
+ By incorporating this functionality, you can give the user the option to see the response in either plain text or a more visually appealing Markdown format.
127
+
128
+ """
129
+ #print("import os")
130
+ import os
131
+ #print("from docx import Document")
132
+ #from docx import Document # to open and interact with Microsoft Word documents (.docx and potentially .doc files).
133
+ #print("import PyPDF2 # Import PyPDF2 library for PDFs")
134
+ #import PyPDF2 # Import PyPDF2 library for PDFs
135
+ #print("from bs4 import BeautifulSoup")
136
+ #from bs4 import BeautifulSoup # Import BeautifulSoup for HTML parsing
137
+ #print("import pyth")
138
+ #import pyth # for extracting plain text from .rtf files.
139
+ #print("import datetime")
140
+ import datetime
141
+ print("import google.generativeai as genai")
142
+ import google.generativeai as genai
143
+
144
+ print("Configure API key (replace with your actual key)")
145
+ #API_KEY = "YOUR_API_KEY"
146
+ GOOGLE_API_KEY = "AI______________FU" # it's recommended to use double quotes (") around the API key value.
147
+ print(f"GOOGLE_API_KEY = {GOOGLE_API_KEY}")
148
+ genai.configure(api_key=GOOGLE_API_KEY)
149
+
150
+ global MODEL_NAME # Declare MODEL_NAME as global
151
+ global NumDocs_Flag, main_index
152
+
153
+ ############# LIST OF AVAILABLE MODELS code direct from Google #####################
154
+ #for m in genai.list_models():
155
+ #if 'generateContent' in m.supported_generation_methods:
156
+ #print(m.name)
157
+ ##################### INDEXED LIST OF AVAILABLE MODELS code generated by Gemini (Bard) ################
158
+ available_models = []
159
+ for i, m in enumerate(genai.list_models()):
160
+ if 'generateContent' in m.supported_generation_methods:
161
+ available_models.append((i + 1, m.name)) # Add model with index
162
+
163
+ print("Available models:")
164
+ for index, model_name in available_models:
165
+ print(f"{index}. {model_name}")
166
+
167
+ while True:
168
+ try:
169
+ user_selection = int(input("Enter the number of the model you want to use: "))
170
+ # Set MODEL_NAME to "gemini-pro" if user selects 0 directly
171
+ if user_selection == 0: #if user_selection = 0, then MODEL_NAME = "gemini-pro" and break
172
+ MODEL_NAME = "gemini-pro"
173
+ break
174
+
175
+ #selected_index = user_selection - 1
176
+ selected_index = user_selection - 4 # because list starts at 4.
177
+ if 0 <= selected_index < len(available_models):
178
+ MODEL_NAME = available_models[selected_index][1] # Access model name
179
+ break
180
+ else:
181
+ print("Invalid selection. Please choose a number from the list.")
182
+ except ValueError:
183
+ print("Invalid input. Please enter a valid integer.")
184
+
185
+ print("Selected model:", MODEL_NAME)
186
+
187
+ ############################ ACTIVATE SELECTED MODEL ################################
188
+
189
+ # Assuming you have already imported the model
190
+ #model = genai.GenerativeModel('gemini-pro')
191
+
192
+ #MODEL_NAME = "gemini-pro"
193
+ model = genai.GenerativeModel(MODEL_NAME)
194
+
195
+ ############# PRINT STATs for the SELECTED MODEL - NOT WORKING ###############
196
+ #print(f"model.config = {model.config}") # AttributeError: 'GenerativeModel' object has no attribute 'config'
197
+ #print(f"genai.config = {genai.config}") # AttributeError: module 'google.generativeai' has no attribute 'config'. Did you mean: 'configure'?'
198
+ #print("model.config = " + str(model.config))
199
+
200
+ #try: #Model doesn't have a direct 'max_input_length' attribute.
201
+ # Check for direct attribute access
202
+ #print("Maximum input token length (direct attribute):", model.max_input_length)
203
+ #except AttributeError:
204
+ #print("Model doesn't have a direct 'max_input_length' attribute.")
205
+
206
+ #try: #Model configuration doesn't have a 'max_input_length' attribute.
207
+ # Check within model configuration
208
+ #print("Maximum input token length (configuration):", model.config.max_input_length)
209
+ #except AttributeError:
210
+ #print("Model configuration doesn't have a 'max_input_length' attribute.")
211
+
212
+
213
+ ######################### FOLDERS #####################################
214
+ #print("Define folders")
215
+ input_documents_folder = "input_documents_folder"
216
+ output_responses_folder = "output_responses_folder"
217
+ log_folder = "log_folder"
218
+
219
+ # Create input_documents_folder if it doesn't exist
220
+ os.makedirs(output_responses_folder, exist_ok=True)
221
+
222
+ # Create output_responses_folder if it doesn't exist
223
+ os.makedirs(output_responses_folder, exist_ok=True)
224
+
225
+ # Create log folder if it doesn't exist
226
+ os.makedirs(log_folder, exist_ok=True)
227
+
228
+
229
+ #################### Pre-initialize API variables -response- and -response.text- ######################3
230
+ # Initialize response and response.text (filled by the API) with a placeholder (not recommended)
231
+ #response = None # triggers an error: AttributeError: 'NoneType' object has no attribute 'text'
232
+ #response = "" # triggers an error: AttributeError: 'str' object has no attribute 'text'
233
+ #response.text = "" #(empty string)
234
+
235
+ ## ############### Needs Simplification ############
236
+ #print("Manufacture a fake API to define response and response.text before real API call to Gemini.")
237
+ class FakeResponse:
238
+ def __init__(self, text):
239
+ self.text = text
240
+
241
+ def get_response_from_api():
242
+ # Simulate an API call (no actual network interaction)
243
+ #fake_response = FakeResponse("This is fake API response text.")
244
+ fake_response = FakeResponse(" ") # use this in final to eliminate.
245
+ return fake_response
246
+
247
+ # Example usage
248
+ response = get_response_from_api()
249
+
250
+ if response is not None:
251
+ response_text = response.text + "\n" # to allign with the User:, Assistant: separeate-lines, motif below.
252
+ #print(f" Fake Response = {response_text}") # Prints "This is fake API response text."
253
+ else:
254
+ print("No response received from Fake API")
255
+
256
+ ###################################### def load_and_select_input_documents #################################
257
+ def load_and_select_input_documents():
258
+ #Loads filenames, prints an indexed list, prompts user for selection, and loads text sequentially.
259
+
260
+ # Get document filenames
261
+ supported_extensions = (".pdf", ".html", ".mhtml", ".txt", ".py", ".rtf", ".docx", ".doc")
262
+ filenames = [filename for filename in os.listdir(input_documents_folder)
263
+ if filename.lower().endswith(supported_extensions)]
264
+
265
+ # Print numbered list of filenames
266
+ print("Available Documents:")
267
+ for i, filename in enumerate(filenames):
268
+ print(f"{i+1}. {filename}")
269
+ print("")
270
+ print(f"MODEL_NAME = {MODEL_NAME}") # remined of selected model type.
271
+
272
+ #print("Get user input for document selection")
273
+ while True:
274
+ selected_input = input("Select document numbers (comma-separated): ")
275
+ try:
276
+ # Check for zero selection (exit to main)
277
+ if selected_input == '0':
278
+ print("User has selected 0 documents. Return to main loop with emptly combined_text, and NumDocs_Flag = 0") # NumDocs_Flag is global for indicating that zero documents in use, and bypass inapplicables. not yet implemented.
279
+ global NumDocs_Flag, main_index
280
+ NumDocs_Flag = 0 # Set the global NumDocs_Flag for future use (if applicable)
281
+ combined_text = "" # empty. no documents in combined text
282
+ main_index =0
283
+ output_filename =f"FreePrompt{main_index + 1}"
284
+ return combined_text, output_filename #exit to main with these values
285
+
286
+ selected_indices = [int(x) - 1 for x in selected_input.split(",")] # Adjust for 0-based indexing
287
+ if all(0 <= index < len(filenames) for index in selected_indices):
288
+ # create a list of selected_indices plus one
289
+ selected_indices_plus_one = [index + 1 for index in selected_indices]
290
+ # Print the list using f-string for formatting
291
+ print(f"Documents {selected_indices_plus_one} have been selected")
292
+ break
293
+ else:
294
+ print("Invalid selection. Please enter comma-separated numbers within the available range.")
295
+ except ValueError:
296
+ print("Invalid input. Please enter comma-separated numbers.")
297
+
298
+ #print("Load text from selected documents in specified order")
299
+ combined_text = ""
300
+ for index in selected_indices:
301
+ filename = filenames[index]
302
+ filepath = os.path.join(input_documents_folder, filename)
303
+
304
+ if filename.lower().endswith(".docx"): # Handle .docx files
305
+ #print("from docx import Document")
306
+ from docx import Document # to open and interact with Microsoft Word documents (.docx and potentially .doc files).
307
+ try:
308
+ document = Document(filepath)
309
+ #document = docx.Document(filepath) use only if import docx # Imports the entire docx library
310
+ combined_text += f"[Document #{index + 1} = {filename}]\n"
311
+ for paragraph in document.paragraphs:
312
+ combined_text += f"{paragraph.text}\n"
313
+ except Exception as e:
314
+ print(f"Error processing {filename}: {e}") # Handle potential errors
315
+
316
+ #elif filename.lower().endswith(".doc"): # TYPICALLY CRASHES. Consider using a different library for .doc files
317
+ #print(f"Cannot handle .doc files directly. Consider using a library like python-docx2txt for .doc files.")
318
+ elif filename.lower().endswith(".doc"): # Handle .doc files
319
+ #print("from docx import Document")
320
+ from docx import Document # to open and interact with Microsoft Word documents (.docx and potentially .doc files).
321
+ try:
322
+ document = Document(filepath)
323
+ combined_text += f"[Document #{index + 1} = {filename}]\n" # Insert document name once
324
+ for paragraph in document.paragraphs:
325
+ combined_text = combined_text + f"[{paragraph.text}\n"
326
+ combined_text += f"{paragraph.text}\n" # Append paragraph text
327
+ except Exception as e:
328
+ print(f"Error processing {filename}: {e}")
329
+ print(f"Attempting to extract text with Textract...")
330
+ import textract # Import Textract only if needed
331
+ text = textract.process(filepath).decode('utf-8')
332
+ combined_text += f"[Document #{index + 1} = {filename} (Textract)]\n" # Indicate Textract usage
333
+ combined_text += text # Append extract-extracted text
334
+
335
+ elif filename.lower().endswith(".pdf"): # Handle .pdf files
336
+ #print("import PyPDF2 # Import PyPDF2 library for PDFs") #libraries like PyPDF2, Camelot, or PDFMiner.six can extract text from PDF documents.
337
+ import PyPDF2 # Import PyPDF2 library for PDFs
338
+ try:
339
+ with open(filepath, 'rb') as pdf_file: # Open PDF in binary mode
340
+ pdf_reader = PyPDF2.PdfReader(pdf_file)
341
+ for page_num in range(len(pdf_reader.pages)): # Iterate through pages
342
+ page_obj = pdf_reader.pages[page_num]
343
+ text = page_obj.extract_text() # Extract text from each page
344
+ combined_text += f"[Document #{index + 1} = {filename} - Page {page_num + 1}]\n{text}\n"
345
+ except Exception as e:
346
+ print(f"Error processing {filename}: {e}") # Handle potential errors
347
+
348
+ elif filename.lower().endswith(".html") or filename.lower().endswith(".mhtml"): # Handle .html and .mhtml pages
349
+ #print("from bs4 import BeautifulSoup")
350
+ from bs4 import BeautifulSoup # Import BeautifulSoup for HTML parsing
351
+ try:
352
+ #with open(filepath, "r") as html_file: # Open HTML file in read mode #to open the file directly in text mode without BeautifulSoup, use 'r'
353
+ #soup = BeautifulSoup(html_file, "html.parser") # Parse HTML structure
354
+ with open(filepath, 'rb') as f:
355
+ soup = BeautifulSoup(f, 'html.parser')
356
+ combined_text += f"[Document #{index + 1} = {filename}]\n" # Insert document name
357
+ for paragraph in soup.find_all("p"): # Find all <p> elements (paragraphs)
358
+ combined_text += f"{paragraph.get_text(strip=True)}\n" # Extract text, strip whitespace
359
+ except Exception as e:
360
+ print(f"Error processing {filename}: {e}") # Handle potential errors
361
+
362
+ elif filename.lower().endswith(".rtf"): # Handle .rtf files
363
+ print("import pyth")
364
+ import pyth # for extracting plain text from .rtf files.
365
+ try:
366
+ with open(filepath, "r") as rtf_file:
367
+ rtf_content = rtf_file.read()
368
+ text = pyth.decode(rtf_content) # Extract text using pyth assumes you've installed pyth using pip install pyth.
369
+ combined_text += f"[Document #{index + 1} = {filename}]\n{text}\n"
370
+ except Exception as e:
371
+ print(f"Error processing {filename}: {e}")
372
+
373
+ else:
374
+ try: # Handle other text files (e.g., .txt) with default encoding
375
+ with open(filepath, 'r', encoding='utf-8') as f:
376
+ combined_text += f.read() + "\n\n"
377
+ except UnicodeDecodeError as e:
378
+ print(f"Error decoding {filename} with 'utf-8' encoding: {e}")
379
+
380
+ # Generate output filename based on selected filenames
381
+ #output_filename = "_".join([filenames[i] for i in selected_indices])
382
+ # Ensure .txt extension for output filename
383
+ output_filename = f"_".join([filenames[i] for i in selected_indices]) #+ ".txt"
384
+ #limit length of output_filename:
385
+ max_filename_length = 40
386
+ # Truncate only if necessary
387
+ if len(output_filename) > max_filename_length:
388
+ output_filename = output_filename[:max_filename_length] + "__.txt"
389
+
390
+ token_count = model.count_tokens(combined_text)
391
+ print(f"Number of tokens in combined_text: {token_count}")
392
+ return combined_text, output_filename
393
+
394
+
395
+ ###################################### def load_and_select_input_IMAGEs #################################
396
+ def load_and_select_input_IMAGEs(): # STUB. NOT YET IMPLEMENTED, nor called by main.
397
+
398
+ #Loads filenames, prints an indexed list, prompts user for selection, and loads IMAGES sequentially.
399
+
400
+ # Get image filenames
401
+ supported_extensions = (".jpg", ".jpeg", ".png", ".webx",".tif", ".gif", ".psd", ".bmp")
402
+ filenames = [filename for filename in os.listdir(input_documents_folder)
403
+ if filename.lower().endswith(supported_extensions)]
404
+
405
+ # Print numbered list of IMAGE filenames
406
+ print("Available IMAGES:")
407
+ for i, filename in enumerate(fileames):
408
+ print(f"{i+1}. {filename}")
409
+ print("")
410
+ print(f"MODEL_NAME = {MODEL_NAME}") # remind of selected model type.
411
+
412
+ # User-select Image File(s) here. Same as in Documents.
413
+
414
+ for index in selected_indices:
415
+ filename = filenames[index]
416
+ filepath = os.path.join(input_documents_folder, filename)
417
+
418
+ if filename.lower().endswith(".jpg"): # Handle .jpg files
419
+ # Import the jpg file.
420
+ import PIL.Image
421
+ elif filename.lower().endswith(".png"): # Handle .png files
422
+
423
+ #STUFF FROM GOOGLE QUICKSTART HTML Page.
424
+ import PIL.Image
425
+ model = genai.GenerativeModel('gemini-pro-vision')
426
+ #MODEL_NAME = "gemini-pro"
427
+ #model = genai.GenerativeModel(MODEL_NAME)
428
+ combined_text = f"imagename.jpg"
429
+ img = PIL.Image.open('image.jpg')
430
+ #response = model.generate_content(img)
431
+ #To provide both text and images in a prompt, pass a list containing the strings and images:
432
+ response = model.generate_content(["Write a short, engaging blog post based on this picture. It should include a description of the meal in the photo and talk about my journey meal prepping.", img], stream=True)
433
+ response.resolve() # only required because stream=True
434
+ to_markdown(response.text)
435
+
436
+
437
+ ########################################## def Construct_Prompt_and_Response #####################################
438
+ def Construct_Prompt_and_Response(instructions, combined_text):
439
+ #def Construct_Prompt_and_Print_Log_Response(combined_text, MODEL_NAME, log_folder, output_responses_folder):
440
+ #receives instructions and combined_text, sends them as prompt to the generative model,
441
+ #prints and logs the response, and saves the prompt (instructions only) and response to an output/log file.
442
+
443
+ # Construct the prompt using both instructions and combined_text
444
+ prompt = f"{instructions}: {combined_text}"
445
+ # Send prompt to model to obtain a response
446
+ response = model.generate_content(prompt)
447
+ #response.text = f"Gemini AI: {response.text}\n" # Bard says: The error message "can't set attribute 'text'" in the line response.text = f"Gemini AI: {response.text}\n" indicates that the object referred to by response doesn't allow modifying its text property. The error message implies that the text property of the response object is not designed to be changed directly in your code. It might be a read-only property or have internal logic that manages its content. Libraries or models often return objects with specific structures and properties to manage their data internally. Modifying these properties directly within your code can lead to unexpected behavior or errors.
448
+ #response.text = "Gemini AI: " + response.text + "\n" # line n is for separation when combined below. #Assume the GenerateContentResponse object has a property named text that holds the actual generated content.
449
+ # Return response
450
+ return response
451
+
452
+ #################### def Log_response_and_Save_Instructions_and_Response_to_output_file ##########################
453
+ def Log_response_and_Save_Instructions_and_Response_to_output_file(instructions, response, output_filename, main_index):
454
+ #print(f"Gemini Response:\n{response.text}") # for debugging only.
455
+ print("") # space
456
+ # Use the globally defined folders
457
+ global log_folder, output_responses_folder
458
+
459
+ today = datetime.date.today().strftime("%Y-%m-%d")
460
+ #print(f"Get today's date: {today}")
461
+ log_file = os.path.join(log_folder, f"{today}.log")
462
+
463
+ # Extract input_filename without ".txt"
464
+ input_files = output_filename.replace(".txt", "")
465
+
466
+ # Write instructions and response to All-Day Today log file
467
+ with open(log_file, 'a') as f:
468
+ f.write(f"Today's date: {today}\n")
469
+ f.write(f"Input Files: {input_files}\n")
470
+ f.write(f"Instructions #{main_index + 1}: {instructions}\n")
471
+ f.write(f"Response #{main_index + 1}: {response.text}\n\n")
472
+
473
+ # Log instructions and response to named output file
474
+ #output_filename = # now defined in def load_documents():
475
+ output_path = os.path.join(output_responses_folder, output_filename)
476
+ with open(output_path, 'w') as f:
477
+ f.write(f"Today's date: {today}\n")
478
+ f.write(f"Input Files: {input_files}\n")
479
+ #f.write(f"Instructions: {instructions}\n")
480
+ #f.write(f"Response: {response.text}")
481
+ f.write(f"Instructions #{main_index + 1}: {instructions}\n")
482
+ f.write(f"Response #{main_index + 1}: {response.text}\n\n")
483
+
484
+
485
+ ###################################### def MAIN #################################
486
+ def main(): #Main function to load documents, prompt the user, and generate a response, log and save.
487
+ global response, main_index # to avoid error: UnboundLocalError: local variable 'response' referenced before assignment
488
+ #load and select documents.docx
489
+ combined_text, output_filename = load_and_select_input_documents()
490
+
491
+ # Prompt user for the number of iterations
492
+ #num_iterations = int(input("Enter the number of iterations: "))
493
+ while True:
494
+ try:
495
+ num_iterations_str = input("Enter the number of iterations: ")
496
+ num_iterations = int(num_iterations_str)
497
+ # If execution reaches here, the input was a valid integer
498
+ break # Exit the loop
499
+ except ValueError:
500
+ print("Invalid input. Please enter a positive integer.")
501
+
502
+ # Proceed with further code using num_iterations
503
+
504
+ # Prompt user for instructions
505
+ instructions = input("Enter instructions for Gemini model (e.g., summarize, explain key concepts, combine): ")
506
+ print("") # space
507
+
508
+ for main_index in range(num_iterations):
509
+ # Construct prompt, get response, and log/save
510
+ response = Construct_Prompt_and_Response(instructions, combined_text)
511
+
512
+ # Print instructions and response
513
+ print(f"Instructions #{main_index + 1}: {instructions}")
514
+ # Use 'is None' to check for null response.text and print prompt feedback if applicable
515
+ if response.text is None:
516
+ print(f"Response prompt_feedback = {response.prompt_feedback}")
517
+ else:
518
+ print(f"Response #{main_index + 1}: {response.text}")
519
+ if not response.text: # Check if response.text is empty
520
+ safety_ratings = response.candidates[0].safety_ratings # Access safety ratings from first candidate
521
+ if any(rating.rating == "BLOCK" for rating in safety_ratings):
522
+ print(f"Response blocked due to safety concerns: {safety_ratings}")
523
+ else:
524
+ print("An error occurred while processing the prompt. Please try again.")
525
+
526
+ Log_response_and_Save_Instructions_and_Response_to_output_file(instructions, response, output_filename, main_index)
527
+
528
+ # Re-prompt for instructions for the next iteration (if needed)
529
+ if main_index + 1 < num_iterations:
530
+ new_instructions = input("Enter instructions for the next iteration (or press Enter to continue with same instructions): ")
531
+ if new_instructions:
532
+ instructions = new_instructions # Assuming you want to use new instructions
533
+
534
+ ############## After Documents, after last "iteration", free form prompts without documents:
535
+
536
+
537
+ # Probably going to want to convert this to
538
+ #model = genai.GenerativeModel('gemini-pro')
539
+ #chat = model.start_chat(history=[])
540
+ #chat
541
+ #response = chat.send_message("In one sentence, explain how a computer works to a young child.")
542
+ #to_markdown(response.text)
543
+
544
+ combined_text = response.text # carries the last-prior response, or fake API response, forward (e.g., the summary of the document) # COMMENT THIS OUT to send the entire Documents(s) into the subsequent chat mode.
545
+
546
+ #combined_text = "" # empties completely.
547
+ #if response is not None and response.text is not None:
548
+ #combined_text = response.text # carries the last-prior response forward (e.g., the summary of the document)
549
+ #else:
550
+ #combined_text = "" # Assign an empty string if response is None or its text is None
551
+ #print("response = None, and combined_text = empty")
552
+
553
+ print(" Further prompts for Gemini model includes the last above but no whole documents attached:")
554
+ print("")
555
+ while True: # Infinite Loop (while True): script continues running until you manually stop (using Ctrl+C).
556
+ main_index += 1
557
+ #print(f"END OF CURRENT RESPONSE. The main_index = {main_index}, The Combined_text = {combined_text}")
558
+ print(f"END OF CURRENT RESPONSE. The main_index = {main_index}")
559
+ instructions = "User: " + input(f"Prompt #{main_index + 1} ") #Concatenates the string "User: " with the user's input, ensuring every prompt starts with "User: ".
560
+ # Construct prompt, get response, and log/save
561
+ response = Construct_Prompt_and_Response(combined_text, instructions) # switched order of instructions/firsttext=0)
562
+
563
+ # Print instructions and response
564
+ #print(f"Prompt #{main_index + 1}: {instructions}")
565
+ print("") #space.
566
+ if not response.text: # Check if response.text is empty
567
+ safety_ratings = response.candidates[0].safety_ratings # Access safety ratings from first candidate
568
+ if any(rating.rating == "BLOCK" for rating in safety_ratings):
569
+ print(f"Response blocked due to safety concerns: {safety_ratings}")
570
+ else:
571
+ print("An error occurred while processing the prompt. Please try again.")
572
+ if response.text:
573
+ print(f"Response #{main_index + 1}: {response.text}")
574
+ else:
575
+ print("An error occurred or the response was blocked. Check logs for details.")
576
+ if response.text is None: # Use 'is None' to check for null response.text and print prompt feedback if applicable
577
+ print(f"Response Feedback = {response.prompt_feedback}")
578
+ print("") #space.
579
+ #combined_text = str(combined_text) # Assuming it was previously accidentally a tuple or a set ()
580
+ combined_text += f"{instructions}.\n Assistant: {response.text}\n" # pass through again the prior dialogue.
581
+
582
+ #output_filename =f"FreePrompt{main_index + 1}"
583
+ #Log_response_and_Save_Instructions_and_Response_to_output_file(instructions, response, output_filename, main_index)
584
+
585
+ if __name__ == "__main__":
586
+ main()