Spaces:
Running
Running
File size: 8,257 Bytes
4699d61 38af1b1 3e78d5c 4699d61 24e4972 1795c94 4699d61 c8156cc c556a1e 4699d61 799d8f9 d9259e5 c8156cc 4699d61 d0fefeb 4699d61 59d7eb8 4699d61 c8156cc 4699d61 fd61500 1991fd4 d4403c2 2682bf9 fd61500 4699d61 45d0d6b a1f2bf6 45d0d6b c8156cc 2e87939 4699d61 4fc00a2 fd61500 10837a2 4699d61 326bfe4 fd61500 10837a2 4699d61 d0fefeb 45d0d6b a1f2bf6 10837a2 2e34aea d9f7a6d 9754a79 59d7eb8 2e34aea e76c1af fd61500 22c1da4 2a8b254 59d7eb8 74016ec e76c1af fd61500 22c1da4 e76c1af 4699d61 59d7eb8 2e34aea e76c1af bee28e6 45d0d6b 1795c94 4699d61 a3d3af1 8a0fcb8 4699d61 59d7eb8 c8156cc 59d7eb8 2e34aea 59d7eb8 0da7b5b 59d7eb8 9754a79 d9f7a6d 59d7eb8 9754a79 3e78d5c 2e34aea 5907d8c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
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() |