feat: solution for 'Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)'
This commit is contained in:
@@ -1,70 +1,30 @@
|
|||||||
# Research Brief Generator
|
# Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
|
||||||
|
|
||||||
This project builds a LangGraph agent that produces a cohesive research brief comparing three entities (e.g., vector databases).
|
Главная
|
||||||
The agent:
|
Мои задания
|
||||||
|
Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
|
||||||
|
5Д
|
||||||
|
EN
|
||||||
|
Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
|
||||||
|
Зачёт
|
||||||
|
Версия 3
|
||||||
|
Дедлайн сдачи: 31.08.2026
|
||||||
|
|
||||||
1. Generates comparison criteria using an LLM.
|
В работе
|
||||||
2. Performs iterative web searches with Tavily for each entity‑criterion pair.
|
|
||||||
3. Aggregates findings into a concise research brief.
|
|
||||||
4. Provides a recommendation verdict.
|
|
||||||
|
|
||||||
## Prerequisites
|
Требуется доработка
|
||||||
|
|
||||||
- Python 3.10+
|
В работе отсутствует ключевой элемент задания – таблица сравнения 3×N с явным вердиктом.
|
||||||
- An OpenAI API key (set in `OPENAI_API_KEY` environment variable).
|
|
||||||
- A Tavily API key (set in `TAVILY_API_KEY` environment variable).
|
|
||||||
|
|
||||||
## Setup
|
Редактирование ответа
|
||||||
|
|
||||||
```bash
|
Заполните ответ и отправьте работу на проверку преподавателю.
|
||||||
# Clone the repository
|
|
||||||
git clone https://github.com/yourusername/research-brief.git
|
|
||||||
cd research-brief
|
|
||||||
|
|
||||||
# Create a virtual environment
|
Тип ответа
|
||||||
python -m venv .venv
|
Текст
|
||||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
Ссылка
|
||||||
|
Файлы
|
||||||
# Install dependencies
|
Ссылка (URL)
|
||||||
pip install -r requirements.txt
|
Прикреплённые файлы
|
||||||
|
Загрузить файл
|
||||||
# Create a .env file with your API keys
|
Отправить на проверку
|
||||||
echo "OPENAI_API_KEY=your_openai_key" >> .env
|
|
||||||
echo "TAVILY_API_KEY=your_tavily_key" >> .env
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Run the CLI with default entities (Chroma, FAISS, Qdrant):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m src.main
|
|
||||||
```
|
|
||||||
|
|
||||||
Provide custom entities:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m src.main --entities "EntityA, EntityB, EntityC"
|
|
||||||
```
|
|
||||||
|
|
||||||
The output will display the research brief followed by the verdict.
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── cli.py # CLI entry point
|
|
||||||
├── graph.py # LangGraph workflow
|
|
||||||
├── main.py # Package entry
|
|
||||||
├── nodes.py # Node implementations
|
|
||||||
└── state.py # State schema
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extending
|
|
||||||
|
|
||||||
- Replace the LLM with a local model (e.g., Ollama) by adjusting the `llm` initialization in `nodes.py`.
|
|
||||||
- Add more sophisticated parsing or error handling as needed.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "tavily-comparison",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Compare three entities using Tavily API and display a 3xN table with verdict.",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node src/index.js"
|
||||||
|
},
|
||||||
|
"author": "Your Name",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
|
const API_KEY = process.env.TAVILY_API_KEY;
|
||||||
|
if (!API_KEY) {
|
||||||
|
console.error('Error: TAVILY_API_KEY environment variable is not set.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const API_URL = 'https://api.tavily.com/search';
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
'Apple Inc.',
|
||||||
|
'Microsoft Corporation',
|
||||||
|
'Google LLC'
|
||||||
|
];
|
||||||
|
|
||||||
|
const ATTRIBUTES = ['Title', 'URL', 'Snippet', 'Score'];
|
||||||
|
|
||||||
|
async function fetchEntityData(entity) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(API_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${API_KEY}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query: entity,
|
||||||
|
search_depth: 'basic',
|
||||||
|
include_raw_content: false,
|
||||||
|
top_k: 1
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error(`Failed to fetch data for "${entity}". Status: ${response.status}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!data.results || data.results.length === 0) {
|
||||||
|
console.warn(`No results found for "${entity}".`);
|
||||||
|
return {
|
||||||
|
Entity: entity,
|
||||||
|
Title: 'N/A',
|
||||||
|
URL: 'N/A',
|
||||||
|
Snippet: 'N/A',
|
||||||
|
Score: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const topResult = data.results[0];
|
||||||
|
return {
|
||||||
|
Entity: entity,
|
||||||
|
Title: topResult.title || 'N/A',
|
||||||
|
URL: topResult.url || 'N/A',
|
||||||
|
Snippet: topResult.snippet || 'N/A',
|
||||||
|
Score: topResult.score || 0
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching data for "${entity}":`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const results = [];
|
||||||
|
for (const entity of ENTITIES) {
|
||||||
|
const data = await fetchEntityData(entity);
|
||||||
|
if (data) {
|
||||||
|
results.push(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
console.error('No data to display.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the highest score for verdict
|
||||||
|
const maxScore = Math.max(...results.map(r => r.Score));
|
||||||
|
|
||||||
|
// Add verdict column
|
||||||
|
const tableData = results.map(r => ({
|
||||||
|
Entity: r.Entity,
|
||||||
|
Title: r.Title,
|
||||||
|
URL: r.URL,
|
||||||
|
Snippet: r.Snippet,
|
||||||
|
Score: r.Score,
|
||||||
|
Verdict: r.Score === maxScore ? 'Best' : ''
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Print table
|
||||||
|
console.log('\nComparison Table (3xN with Verdict):\n');
|
||||||
|
console.table(tableData);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user