File size: 6,581 Bytes
c02e3db
2f96bb8
 
71a8799
2f96bb8
9b5b26a
6cdbdc2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16edca8
6cdbdc2
f8b4531
b80cbf1
7233de1
74e8501
6cdbdc2
b80cbf1
 
74e8501
 
 
 
 
 
b80cbf1
2e6775a
6cdbdc2
 
f8b4531
 
 
6cdbdc2
 
 
 
85e3933
6cdbdc2
f0e61d0
6cdbdc2
c02e3db
6cdbdc2
 
 
f8b4531
 
6cdbdc2
 
 
 
 
 
 
 
f8b4531
6cdbdc2
0f668a0
6cdbdc2
85e3933
f0e61d0
6cdbdc2
 
85e3933
0f668a0
85e3933
34d5e78
cd677bd
2e6775a
 
 
 
 
 
 
cd677bd
2e6775a
 
c02e3db
cd677bd
2e6775a
 
2f96bb8
2e6775a
 
 
 
 
c02e3db
2e6775a
 
 
cd677bd
71a8799
73e52d4
bb8d29a
 
73e52d4
 
 
 
c02e3db
bb8d29a
 
73e52d4
23331b5
148309a
8cf77f5
 
 
 
 
 
c02e3db
 
148309a
bb8d29a
 
 
 
148309a
8cf77f5
cd677bd
71a8799
af62f46
71a8799
 
 
c02e3db
71a8799
9b5b26a
bb8d29a
 
cd677bd
71a8799
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import feedparser
import urllib.parse
import yaml
import gradio as gr
from smolagents import CodeAgent, HfApiModel, tool

# @tool
# def fetch_latest_arxiv_papers(keywords: list, num_results: int = 3) -> list:
#     """Fetches the latest research papers from arXiv based on provided keywords.

#     Args:
#         keywords: A list of keywords to search for relevant papers.
#         num_results: The number of papers to fetch (default is 3).

#     Returns:
#         A list of dictionaries containing:
#             - "title": The title of the research paper.
#             - "authors": The authors of the paper.
#             - "year": The publication year.
#             - "abstract": A summary of the research paper.
#             - "link": A direct link to the paper on arXiv.
#     """
#     try:
#         print(f"DEBUG: Searching arXiv papers with keywords: {keywords}")  # Debug input
        
#         #Properly format query with +AND+ for multiple keywords
#         query = "+AND+".join([f"all:{kw}" for kw in keywords])  
#         query_encoded = urllib.parse.quote(query)  # Encode spaces and special characters
        
#         url = f"http://export.arxiv.org/api/query?search_query={query_encoded}&start=0&max_results={num_results}&sortBy=submittedDate&sortOrder=descending"
        
#         print(f"DEBUG: Query URL - {url}")  # Debug URL
        
#         feed = feedparser.parse(url)

#         papers = []
#         for entry in feed.entries:
#             papers.append({
#                 "title": entry.title,
#                 "authors": ", ".join(author.name for author in entry.authors),
#                 "year": entry.published[:4],  # Extract year
#                 "abstract": entry.summary,
#                 "link": entry.link
#             })

#         return papers

#     except Exception as e:
#         print(f"ERROR: {str(e)}")  # Debug errors
#         return [f"Error fetching research papers: {str(e)}"]

@tool
def fetch_latest_arxiv_papers(keywords: list, num_results: int = 5) -> list:
    """Fetches the latest research papers from arXiv based on provided keywords.

    Args:
        keywords: A list of keywords to search for relevant papers.
        num_results: The number of papers to fetch (default is 5).

    Returns:
        A list of dictionaries containing:
            - "title": The title of the research paper.
            - "authors": The authors of the paper.
            - "year": The publication year.
            - "abstract": A summary of the research paper.
            - "link": A direct link to the paper on arXiv.
    """
    try:
        print(f"DEBUG: Searching arXiv papers with keywords: {keywords}")

        # Format query using "AND" to enforce strict keyword presence
        query = "+AND+".join([f"ti:{kw}+OR+abs:{kw}" for kw in keywords])  
        query_encoded = urllib.parse.quote(query)  # Encode spaces and special characters

        url = f"http://export.arxiv.org/api/query?search_query={query_encoded}&start=0&max_results=20&sortBy=submittedDate&sortOrder=descending"

        print(f"DEBUG: Query URL - {url}")

        feed = feedparser.parse(url)
        papers = []

        for entry in feed.entries:
            title = entry.title.lower()
            abstract = entry.summary.lower()

            # ✅ Ensure at least one keyword appears in the title or abstract
            if any(kw.lower() in title or kw.lower() in abstract for kw in keywords):
                papers.append({
                    "title": entry.title,
                    "authors": ", ".join(author.name for author in entry.authors),
                    "year": entry.published[:4],  # Extract year
                    "abstract": entry.summary,
                    "link": entry.link
                })

        # ✅ Sort papers: First prioritize keyword in title, then abstract
        papers.sort(key=lambda x: sum(kw.lower() in x["title"].lower() for kw in keywords), reverse=True)

        return papers[:num_results]  # Return top-matching papers

    except Exception as e:
        print(f"ERROR: {str(e)}")
        return [{"error": f"Error fetching research papers: {str(e)}"}]




# AI Model
model = HfApiModel(
    max_tokens=2096,
    temperature=0.5,
    model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
    custom_role_conversions=None,
)

# Load prompt templates
with open("prompts.yaml", 'r') as stream:
    prompt_templates = yaml.safe_load(stream)

# Create the AI Agent
agent = CodeAgent(
    model=model,
    tools=[fetch_latest_arxiv_papers],  # Properly registered tool
    max_steps=6,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name="ScholarAgent",
    description="An AI agent that fetches the latest research papers from arXiv based on user-defined keywords and filters.",
    prompt_templates=prompt_templates
)

# Define Gradio Search Function
def search_papers(user_input):
    keywords = [kw.strip() for kw in user_input.split(",") if kw.strip()]  # Ensure valid keywords
    print(f"DEBUG: Received input keywords - {keywords}")  # Debug user input
    
    if not keywords:
        print("DEBUG: No valid keywords provided.")
        return "Error: Please enter at least one valid keyword."
    
    results = fetch_latest_arxiv_papers(keywords, num_results=3)  # Fetch 3 results
    print(f"DEBUG: Results received - {results}")  # Debug function output
    
    if isinstance(results, list) and results and isinstance(results[0], dict):
        #Format output with better readability and clarity
        formatted_results = "\n\n".join([
            f"---\n\n"
            f"📌 **Title:**\n{paper['title']}\n\n"
            f"👨‍🔬 **Authors:**\n{paper['authors']}\n\n"
            f"📅 **Year:** {paper['year']}\n\n"
            f"📖 **Abstract:**\n{paper['abstract'][:500]}... *(truncated for readability)*\n\n"
            f"[🔗 Read Full Paper]({paper['link']})\n\n"
            for paper in results
        ])
        return formatted_results
    
    print("DEBUG: No results found.")
    return "No results found. Try different keywords."



# Create Gradio UI
with gr.Blocks() as demo:
    gr.Markdown("# ScholarAgent")
    keyword_input = gr.Textbox(label="Enter keywords (comma-separated)", placeholder="e.g., deep learning, reinforcement learning")
    output_display = gr.Markdown()
    search_button = gr.Button("Search")

    search_button.click(search_papers, inputs=[keyword_input], outputs=[output_display])

    print("DEBUG: Gradio UI is running. Waiting for user input...")

# Launch Gradio App
demo.launch()