File size: 4,930 Bytes
ec99d5d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from langchain.tools import tool
import subprocess
from langchain_community.tools import DuckDuckGoSearchRun

web_search = DuckDuckGoSearchRun()

@tool
def run_python(code: str) -> str:
    """Eksekusi kode Python secara lokal dan kembalikan output. Gunakan ini untuk melakukan kalkulasi matematika atau memanipulasi data sederhana."""
    try:
        result = subprocess.run(
            ["python", "-c", code],
            capture_output=True, text=True, timeout=10
        )
        return result.stdout or result.stderr
    except subprocess.TimeoutExpired:
        return "Error: Timeout"
    except Exception as e:
        return f"Error: {str(e)}"

import requests
import json
from docx import Document
import os
import uuid
from bs4 import BeautifulSoup
from gtts import gTTS
import pytesseract
from PIL import Image

try:
    from api.agent.knowledge_graph import add_paper_relation, query_graph
except ImportError:
    pass

@tool
def search_crossref(query: str) -> str:
    """Cari jurnal asli dan peer-reviewed di database Crossref."""
    try:
        url = f"https://api.crossref.org/works?query={query}&select=title,author,DOI,published&rows=3"
        response = requests.get(url, timeout=10)
        data = response.json()
        items = data.get("message", {}).get("items", [])
        if not items:
            return "Tidak ada jurnal yang ditemukan di Crossref."
        
        result = "Hasil Pencarian Crossref:\n"
        for item in items:
            title = item.get("title", [""])[0]
            doi = item.get("DOI", "")
            result += f"- Judul: {title} (DOI: {doi})\n"
        return result
    except Exception as e:
        return f"Error mencari di Crossref: {str(e)}"

@tool
def export_to_docx(content: str, title: str = "Hasil Analisis") -> str:
    """Simpan teks yang panjang atau laporan menjadi file Microsoft Word (.docx)."""
    try:
        doc = Document()
        doc.add_heading(title, 0)
        doc.add_paragraph(content)
        
        # Simpan di folder public/exports agar bisa di-download user
        os.makedirs("public/exports", exist_ok=True)
        filename = f"{uuid.uuid4().hex[:8]}.docx"
        filepath = os.path.join("public/exports", filename)
        
        doc.save(filepath)
        return f"File Word berhasil dibuat! Link download: /exports/{filename}"
    except Exception as e:
        return f"Gagal membuat file Word: {str(e)}"

@tool
def read_image_ocr(image_path: str) -> str:
    """Ekstrak teks dari gambar, foto, atau grafik (membutuhkan Tesseract OCR terinstal di sistem)."""
    try:
        if not os.path.exists(image_path):
            return "Gambar tidak ditemukan."
        img = Image.open(image_path)
        text = pytesseract.image_to_string(img, lang='ind+eng')
        return f"Teks yang diekstrak dari gambar:\n{text}"
    except Exception as e:
        return f"Error OCR (Pastikan Tesseract terinstal di sistem operasi): {str(e)}"

@tool
def scrape_website(url: str) -> str:
    """Baca seluruh isi teks dari sebuah halaman web atau jurnal (Web Scraping)."""
    try:
        headers = {'User-Agent': 'Mozilla/5.0'}
        response = requests.get(url, headers=headers, timeout=15)
        soup = BeautifulSoup(response.text, 'html.parser')
        # Ekstrak semua paragraf
        paragraphs = soup.find_all('p')
        text = "\n".join([p.get_text() for p in paragraphs])
        # Batasi output agar tidak terlalu panjang
        return f"Isi Web:\n{text[:3000]}..." if len(text) > 3000 else text
    except Exception as e:
        return f"Gagal membaca website: {str(e)}"

@tool
def synthesize_audio(text: str) -> str:
    """Ubah teks laporan atau rangkuman menjadi file suara Audio (.mp3)."""
    try:
        tts = gTTS(text=text[:5000], lang='id', slow=False)
        os.makedirs("public/audio", exist_ok=True)
        filename = f"{uuid.uuid4().hex[:8]}.mp3"
        filepath = os.path.join("public/audio", filename)
        tts.save(filepath)
        return f"Audio berhasil dibuat! Dengarkan di: /audio/{filename}"
    except Exception as e:
        return f"Gagal membuat audio: {str(e)}"

@tool
def add_to_knowledge_graph(source_paper: str, target_paper: str, relation: str) -> str:
    """Tambahkan relasi antar jurnal ke dalam memori Knowledge Graph (relation: cites, refutes, supports)."""
    try:
        return add_paper_relation(source_paper, target_paper, relation)
    except Exception as e:
        return str(e)

@tool
def query_knowledge_graph(paper_name: str) -> str:
    """Cari jurnal dan silsilah hubungannya di dalam Knowledge Graph."""
    try:
        return query_graph(paper_name)
    except Exception as e:
        return str(e)

# Kumpulan tools yang tersedia untuk agent
AVAILABLE_TOOLS = [
    run_python, calculate_academic_score, web_search, search_crossref, export_to_docx,
    read_image_ocr, scrape_website, synthesize_audio, add_to_knowledge_graph, query_knowledge_graph
]