Pashy's picture
Update app.py
0da7b5b verified
import gradio as gr
import json
import os
from typing import List
from concurrent.futures import ThreadPoolExecutor, as_completed
from openai import OpenAI
import itertools
import ast
# API Keys
OPENAI_API_KEY = os.getenv("YOUR_OPENAI_API_KEY")
openai_client = OpenAI(api_key=OPENAI_API_KEY)
openai_tools = [{"type": "web_search_preview", "search_context_size": "high", "user_location": {"type": "approximate","country": "UA","city": "Kiev"}}]
# JSON parser
def parse_json_response(response: str) -> list:
cleaned = response.replace("json", "").replace("```", "").replace("\n", "")
print(cleaned)
return json.loads(cleaned)
def query_openai(prompt: str) -> str:
try:
response = openai_client.responses.create(
model="gpt-4.1",
temperature=0.5,
max_output_tokens=10000,
tools=openai_tools,
input=prompt,
)
return response.output_text
except Exception as e:
return f"❌ Error: {e}"
# Parallel LLM execution
def run_parallel(prompts: List[str], query_fn, max_workers: int = 5) -> List[str]:
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(query_fn, prompt): prompt for prompt in prompts}
for future in as_completed(futures):
try:
res = parse_json_response(future.result())
results.append(res)
except Exception as e:
print(e)
pass
return results
#Parallel LLM execution
def run_parallel_wo_validation(prompts: List[str], query_fn, max_workers: int = 5) -> List[str]:
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(query_fn, prompt): prompt for prompt in prompts}
for future in as_completed(futures):
results.append(future.result())
return results
# Prompt builders
JSON_INSTRUCTION = 'Поверни list з структурою ["name", "name", ..., "name", "name"]. Поверни тільки цей list. Без будь-якого іншого тексту'
def build_company_prompt(query: str) -> str:
return f"""Твоя задача надати мені список топ 10 компаній, які пов`язані з (входять в) {query}.
Надай список із 10 успішних компаній які відносяться до {query}.
Шукай все що напряму пов'язано з {query}""" + JSON_INSTRUCTION
def build_people_prompt(area: str) -> str:
return f"""Твоя задача надати мені список топ 5 успішних людей, які пов`язані з {area}.
Надай список 5 успішних людей (ім`я та прізвище).
Шукай все що напряму пов'язано з {area} (компанії, дочірні компанії, співробітники, і тд)""" + JSON_INSTRUCTION
def build_books_prompt(name: str, query: str) -> str:
return f"""Ти найкращий пошуковий помічник по книгам у світі. Надай мені список книг, які рекомендував {name}.
Мене цікавлять тільки назви книг та автори, не пиши нічого іншого. В відповіді повинні бути лише назва книги.
Проаналізуй всі статті, публікації, згадки у соціальних мережах про {name} і знайди саме книги які ця людина рекомендувала.
Ці книги потрібні щоб віповісти на запит користувача рекомендації книг від {name} зі сфери {query}.
Якщо ти нічого не зміг знайти поверни "". БІЛЬШЕ НІЧОГО НЕ ПИШИ."""
# Generator function for progressive output
def on_click(query, context):
query = f"{query} {context}".strip() if context else query.strip()
log = ""
log += "🔍 Шукаю пов`язані бізнеси...\n"
yield log.strip(), gr.update(visible=False)
company_responses = run_parallel([build_company_prompt(query)] * 3, query_openai)
company_responses = list(set([item for sublist in company_responses for item in sublist]))
log += "👤 Шукаю найуспішніших людей у цій сфері...\n"
yield log.strip(), gr.update(visible=False)
company_responses.append(query)
print(company_responses)
people_prompts = [build_people_prompt(f"{k} from {query}") for k in list(company_responses)]
people_responses = run_parallel(people_prompts, query_openai)
people_responses = list(set([item for sublist in people_responses for item in sublist]))
print(people_responses)
people = people_responses
log += f"✅ Знайдено людей: {', '.join(people)}\n"
log += "📚 Збираю рекомендації книжок...\n"
yield log.strip(), gr.update(visible=False)
book_prompts = [build_books_prompt(name, query) for name in people]
book_results = run_parallel_wo_validation(book_prompts, query_openai, max_workers=10)
print(book_results)
all_raw_text = " ".join(filter(lambda x: x not in (None, '', '""', "''"), book_results))
#log += all_raw_text
extract_prompt = f"Твоя задача дістати із всього тексту, який я тобі надішлю, всі книги та написати їх автора. Поверни лише назву книги та авторів. Сформуй список із всіх цих книг разом з автором та поверни його. Видали дублікати, якщо вони є. Весь текст: {all_raw_text}. Поверни лише новий список з авторами і нічого більше."
final_response = query_openai(extract_prompt)
books = final_response.strip().split("\n")
def format_books_for_textbox(book_list):
# Filter out empty entries and clean the text
cleaned_books = [book.strip() for book in book_list if book.strip()]
# Remove duplicates while preserving order
seen = set()
unique_books = []
for book in cleaned_books:
if book.lower() not in seen:
seen.add(book.lower())
unique_books.append(book)
# Format with proper line breaks and bullet points
if not unique_books:
return "На жаль, не вдалося знайти рекомендовані книги для цієї сфери."
return "\n\n".join(f"📖 {book}" for book in unique_books)
log += "✅ Готово! Книги, рекомендовані експертами у цій сфері:"
yield log.strip(), gr.update(value=format_books_for_textbox(books), visible=True)
# Gradio interface
with gr.Blocks(title="📚 BookRecommender") as demo:
gr.Markdown("""
# 📚 BookRecommender
Введи сферу або компанію, і ми зберемо книжки, які рекомендують найуспішніші люди в цій галузі.
""")
query_input = gr.Textbox(label="Назва сфери або компанії", placeholder="Наприклад: Universe Group, Genesis, IT-компанії України")
context_input = gr.Textbox(label="Контекст", placeholder="Наприклад: в Україні, на світовому ринку")
search_button = gr.Button("🔍 Знайти книжки")
status_box = gr.Textbox(label="Прогрес виконання", interactive=False)
book_output = gr.Textbox(label="Список рекомендованих книжок", lines=20, interactive=True, visible=False)
search_button.click(
fn=on_click,
inputs=[query_input, context_input],
outputs=[status_box, book_output]
)
if __name__ == "__main__":
demo.launch()