import os import requests import cohere import gradio as gr from typing import List, Dict, Optional import logging from datetime import datetime class GoogleBooksAssistant: # Previous GoogleBooksAssistant class implementation remains the same def __init__(self, cohere_api_key: str, google_books_api_key: str): self.cohere_client = cohere.Client(cohere_api_key) self.google_books_api_key = google_books_api_key self.google_books_base_url = "https://www.googleapis.com/books/v1/volumes" logging.basicConfig(level=logging.INFO) self.logger = logging.getLogger(__name__) def search_books(self, query: str, max_results: int = 5) -> List[Dict]: try: params = { 'q': query, 'key': self.google_books_api_key, 'maxResults': max_results } response = requests.get(self.google_books_base_url, params=params) response.raise_for_status() results = response.json() books = [] for item in results.get('items', []): volume_info = item.get('volumeInfo', {}) books.append({ 'title': volume_info.get('title'), 'authors': volume_info.get('authors', []), 'description': volume_info.get('description', ''), 'categories': volume_info.get('categories', []), 'preview_link': volume_info.get('previewLink'), 'page_count': volume_info.get('pageCount') }) return books except requests.exceptions.RequestException as e: self.logger.error(f"Error searching Google Books API: {str(e)}") return [] def analyze_books(self, books: List[Dict], question: str) -> str: try: context = "\n".join([ f"Book: {book['title']}\n" f"Authors: {', '.join(book['authors'])}\n" f"Description: {book['description']}\n" f"Categories: {', '.join(book['categories'])}\n" for book in books ]) prompt = f"""Based on the following books information: {context} Question: {question} Please provide a detailed analysis of these books in relation to the question. Include relevant comparisons, themes, and insights.""" response = self.cohere_client.generate( model='command', prompt=prompt, max_tokens=500, temperature=0.7, k=0, stop_sequences=[], return_likelihoods='NONE' ) return response.generations[0].text.strip() except Exception as e: self.logger.error(f"Error analyzing books with Cohere: {str(e)}") return "I apologize, but I encountered an error while analyzing the books." def recommend_similar_books(self, book_title: str, max_recommendations: int = 3) -> List[Dict]: try: reference_book = self.search_books(book_title, max_results=1) if not reference_book: return [] categories = reference_book[0].get('categories', []) similar_books = [] for category in categories: query = f"subject:{category}" books = self.search_books( query, max_results=max_recommendations) books = [book for book in books if book['title'] != book_title] similar_books.extend(books) return similar_books[:max_recommendations] except Exception as e: self.logger.error(f"Error recommending similar books: {str(e)}") return [] class GradioInterface: def __init__(self, assistant: GoogleBooksAssistant): self.assistant = assistant def format_book_results(self, books: List[Dict]) -> str: """Format book results for display""" if not books: return "No books found." result = [] for i, book in enumerate(books, 1): result.append(f"📚 Book {i}:") result.append(f"Title: {book['title']}") result.append(f"Authors: {', '.join(book['authors'])}") result.append( f"Description: {book.get('description', 'No description available.')[:200]}...") if book.get('preview_link'): result.append(f"Preview Link: {book['preview_link']}") result.append("") return "\n".join(result) def search_and_display(self, query: str, max_results: int) -> str: """Search books and format results""" books = self.assistant.search_books(query, max_results=max_results) return self.format_book_results(books) def analyze_search_results(self, search_query: str, analysis_question: str, max_results: int) -> tuple: """Search books and provide analysis""" books = self.assistant.search_books( search_query, max_results=max_results) if not books: return "No books found.", "Cannot perform analysis without books." formatted_results = self.format_book_results(books) analysis = self.assistant.analyze_books(books, analysis_question) return formatted_results, analysis def get_recommendations(self, book_title: str, max_recommendations: int) -> str: """Get and format book recommendations""" recommendations = self.assistant.recommend_similar_books( book_title, max_recommendations=max_recommendations ) return self.format_book_results(recommendations) def create_interface(self): """Create the Gradio interface""" with gr.Blocks(title="Google Books AI Assistant") as interface: gr.Markdown(""" # 📚 Google Books AI Assistant Search, analyze, and get recommendations for books using AI-powered analysis. """) with gr.Tab("Search & Analyze"): with gr.Row(): with gr.Column(): search_input = gr.Textbox( label="Search Query", placeholder="Enter your search terms...", lines=1 ) analysis_input = gr.Textbox( label="Analysis Question", placeholder="What would you like to know about these books?", lines=2 ) max_results = gr.Slider( minimum=1, maximum=10, value=5, step=1, label="Maximum Number of Books" ) analyze_btn = gr.Button("Search & Analyze") with gr.Column(): results_output = gr.Textbox( label="Search Results", lines=10, interactive=False # Changed from readonly to interactive=False ) analysis_output = gr.Textbox( label="AI Analysis", lines=10, interactive=False # Changed from readonly to interactive=False ) with gr.Tab("Get Recommendations"): with gr.Row(): with gr.Column(): book_input = gr.Textbox( label="Book Title", placeholder="Enter a book title to get recommendations...", lines=1 ) num_recommendations = gr.Slider( minimum=1, maximum=5, value=3, step=1, label="Number of Recommendations" ) recommend_btn = gr.Button("Get Recommendations") with gr.Column(): recommendations_output = gr.Textbox( label="Recommended Books", lines=10, interactive=False # Changed from readonly to interactive=False ) analyze_btn.click( fn=self.analyze_search_results, inputs=[search_input, analysis_input, max_results], outputs=[results_output, analysis_output] ) recommend_btn.click( fn=self.get_recommendations, inputs=[book_input, num_recommendations], outputs=recommendations_output ) return interface def main(): # Initialize the assistant with API keys assistant = GoogleBooksAssistant( cohere_api_key=os.getenv("COHERE_API_KEY"), google_books_api_key=os.getenv("GOOGLE_BOOKS_API_KEY") ) # Create and launch the Gradio interface gradio_interface = GradioInterface(assistant) interface = gradio_interface.create_interface() interface.launch(share=True) if __name__ == "__main__": main()