Chi-AI-Rookie commited on
Commit
9738813
·
1 Parent(s): 81917a3

The initial update from Qi, solved 2 questions for the timebeing

Browse files
Files changed (4) hide show
  1. .gitignore +40 -0
  2. agent.py +208 -0
  3. app.py +41 -14
  4. requirements.txt +8 -1
.gitignore ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ venv/
25
+ env/
26
+ ENV/
27
+
28
+ # Environment variables
29
+ .env
30
+ .env.local
31
+
32
+ # IDE
33
+ .vscode/
34
+ .idea/
35
+ *.swp
36
+ *.swo
37
+
38
+ # OS
39
+ .DS_Store
40
+ Thumbs.db
agent.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import TypedDict, Annotated
2
+ import os
3
+ from langchain_community.tools import DuckDuckGoSearchRun
4
+ from langchain_community.document_loaders import WikipediaLoader, YoutubeLoader
5
+ from langchain_community.document_loaders.youtube import TranscriptFormat
6
+ from pytube import YouTube
7
+ from langgraph.graph.message import add_messages
8
+ from langchain_core.messages import AnyMessage, HumanMessage, AIMessage
9
+ from langgraph.prebuilt import ToolNode
10
+ from langchain_openai import ChatOpenAI
11
+ from langgraph.graph import START, StateGraph
12
+ from langfuse.langchain import CallbackHandler
13
+ from langgraph.prebuilt import tools_condition
14
+ from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace
15
+ from langchain_core.tools import tool
16
+
17
+ # Web search tool using DuckDuckGo
18
+ search_tool = DuckDuckGoSearchRun()
19
+
20
+ # Create Wikipedia search tool using WikipediaLoader
21
+ @tool
22
+ def search_wikipedia(query: str) -> str:
23
+ """Search Wikipedia for information about a topic.
24
+
25
+ Args:
26
+ query: The search query or topic to look up on Wikipedia
27
+
28
+ Returns:
29
+ str: The Wikipedia content related to the query
30
+ """
31
+ try:
32
+ # Load Wikipedia documents for the query
33
+ loader = WikipediaLoader(query=query, load_max_docs=2)
34
+ docs = loader.load()
35
+
36
+ if not docs:
37
+ return f"No Wikipedia articles found for query: {query}"
38
+
39
+ # Combine the content from the documents
40
+ content = ""
41
+ for doc in docs:
42
+ content += f"Title: {doc.metadata.get('title', 'Unknown')}\n"
43
+ content += f"Content: {doc.page_content}...\n\n"
44
+
45
+ return content
46
+ except Exception as e:
47
+ return f"Error searching Wikipedia: {str(e)}"
48
+
49
+ # Create YouTube transcript analysis tool
50
+ @tool
51
+ def analyze_youtube_video(video_url: str) -> str:
52
+ """Analyze a YouTube video by loading and processing its transcript.
53
+
54
+ Args:
55
+ video_url: The YouTube video URL to analyze
56
+
57
+ Returns:
58
+ str: The transcript content of the YouTube video
59
+ """
60
+ # try:
61
+ # # Method 1: Try with basic YoutubeLoader first
62
+ # try:
63
+ # loader = YoutubeLoader.from_youtube_url(
64
+ # video_url,
65
+ # add_video_info=True,
66
+ # language=["en", "en-US", "en-GB"] # Try multiple English variants
67
+ # )
68
+ # docs = loader.load()
69
+
70
+ # if docs:
71
+ # content = ""
72
+ # for doc in docs:
73
+ # title = doc.metadata.get('title', 'Unknown Video')
74
+ # author = doc.metadata.get('author', 'Unknown Author')
75
+ # length = doc.metadata.get('length', 'Unknown')
76
+
77
+ # content += f"Video Title: {title}\n"
78
+ # content += f"Author: {author}\n"
79
+ # content += f"Length: {length} seconds\n"
80
+ # content += f"Transcript:\n{doc.page_content}\n\n"
81
+
82
+ # return content
83
+ # except Exception as e1:
84
+ # print(f"Method 1 failed: {e1}")
85
+
86
+ # Method 2: Try without video info
87
+ # try:
88
+ # loader = YoutubeLoader.from_youtube_url(
89
+ # video_url,
90
+ # add_video_info=False,
91
+ # language=["en"]
92
+ # )
93
+ # docs = loader.load()
94
+
95
+ # if docs:
96
+ # content = f"Video URL: {video_url}\n"
97
+ # content += f"Transcript:\n{docs[0].page_content}\n\n"
98
+ # return content
99
+ # except Exception as e2:
100
+ # print(f"Method 2 failed: {e2}")
101
+
102
+ # # Method 3: Try with chunked format
103
+ try:
104
+ loader = YoutubeLoader.from_youtube_url(
105
+ video_url,
106
+ add_video_info=False,
107
+ transcript_format=TranscriptFormat.CHUNKS,
108
+ chunk_size_seconds=60
109
+ )
110
+ docs = loader.load()
111
+
112
+ if docs:
113
+ content = f"Video URL: {video_url}\n"
114
+ content += "Transcript (Chunked):\n"
115
+ for i, doc in enumerate(docs[:5]): # Limit to first 5 chunks
116
+ content += f"Chunk {i+1}: {doc.page_content}\n"
117
+ return content
118
+ except Exception as e:
119
+ print(f"Analyze video failed: {e}")
120
+
121
+ # Initialize Langfuse CallbackHandler globally
122
+ def get_langfuse_handler():
123
+ """Get configured Langfuse handler"""
124
+ # Langfuse will automatically read LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, and LANGFUSE_HOST from environment
125
+ return CallbackHandler()
126
+
127
+ def build_jasper():
128
+ # Generate the chat interface, including the tools
129
+ # llm = HuggingFaceEndpoint(
130
+ # repo_id="Qwen/Qwen2.5-Coder-32B-Instruct",
131
+ # huggingfacehub_api_token=os.getenv("HUGGINGFACE_API_TOKEN"),
132
+ # )
133
+
134
+ tools = [search_tool, search_wikipedia, analyze_youtube_video]
135
+
136
+ # llm = HuggingFaceEndpoint(
137
+ # repo_id="Qwen/Qwen2.5-Omni-3B",
138
+ # huggingfacehub_api_token=os.getenv("HUGGINGFACE_API_TOKEN"),
139
+ # )
140
+ # chat = ChatHuggingFace(llm=llm, verbose=True)
141
+ # chat_with_tools = chat.bind_tools(tools)
142
+
143
+ # Set your OpenAI API key here
144
+ llm = ChatOpenAI(
145
+ model="gpt-4o",
146
+ temperature=0,
147
+ api_key=os.getenv("OPENAI_API_KEY")
148
+ )
149
+ chat_with_tools = llm.bind_tools(tools, parallel_tool_calls=False)
150
+
151
+
152
+ # Generate the AgentState and Agent graph
153
+ class AgentState(TypedDict):
154
+ messages: Annotated[list[AnyMessage], add_messages]
155
+
156
+
157
+ def assistant(state: AgentState):
158
+ return {
159
+ "messages": [chat_with_tools.invoke(state["messages"])],
160
+ }
161
+
162
+ ## The graph
163
+ builder = StateGraph(AgentState)
164
+
165
+ # Define nodes: these do the work
166
+ builder.add_node("assistant", assistant)
167
+ builder.add_node("tools", ToolNode(tools))
168
+
169
+ # Define edges: these determine how the control flow moves
170
+ builder.add_edge(START, "assistant")
171
+ builder.add_conditional_edges(
172
+ "assistant",
173
+ # If the latest message requires a tool, route to tools
174
+ # Otherwise, provide a direct response
175
+ tools_condition,
176
+ )
177
+ builder.add_edge("tools", "assistant")
178
+
179
+ # Compile the graph without callback parameter
180
+ jasper = builder.compile()
181
+ print("Langfuse tracing enabled - traces will be available in your Langfuse dashboard")
182
+ return jasper
183
+
184
+ def run_jasper():
185
+ jasper = build_jasper()
186
+ messages = [HumanMessage(content="Examine the video at https://www.youtube.com/watch?v=1htKBjuUWec.\n\nWhat does Teal'c say in response to the question \"Isn't that hot?\"")]
187
+
188
+ # Get Langfuse handler for tracing
189
+ langfuse_handler = get_langfuse_handler()
190
+
191
+ # Add trace metadata for this specific run
192
+ response = jasper.invoke(
193
+ {"messages": messages},
194
+ config={
195
+ "callbacks": [langfuse_handler],
196
+ "metadata": {
197
+ "trace_name": "YouTube_Video_Analysis",
198
+ "user_id": "jasper-user",
199
+ "session_id": "jasper-agent-session"
200
+ }
201
+ }
202
+ )
203
+
204
+ print("Jasper's Response:")
205
+ print(response['messages'][-1].content)
206
+
207
+ if __name__ == "__main__":
208
+ run_jasper()
app.py CHANGED
@@ -3,25 +3,49 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
 
 
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
- # --- Basic Agent Definition ---
12
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
- class BasicAgent:
14
  def __init__(self):
15
- print("BasicAgent initialized.")
16
- def __call__(self, question: str) -> str:
17
- print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  def run_and_submit_all( profile: gr.OAuthProfile | None):
23
  """
24
- Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
@@ -40,7 +64,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
40
 
41
  # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
- agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
@@ -80,7 +104,8 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
80
  print(f"Skipping item with missing task_id or question: {item}")
81
  continue
82
  try:
83
- submitted_answer = agent(question_text)
 
84
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
  except Exception as e:
@@ -107,7 +132,8 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
107
  f"User: {result_data.get('username')}\n"
108
  f"Overall Score: {result_data.get('score', 'N/A')}% "
109
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
110
- f"Message: {result_data.get('message', 'No message received.')}"
 
111
  )
112
  print("Submission successful.")
113
  results_df = pd.DataFrame(results_log)
@@ -142,7 +168,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
142
 
143
  # --- Build Gradio Interface using Blocks ---
144
  with gr.Blocks() as demo:
145
- gr.Markdown("# Basic Agent Evaluation Runner")
146
  gr.Markdown(
147
  """
148
  **Instructions:**
@@ -150,6 +176,7 @@ with gr.Blocks() as demo:
150
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
153
 
154
  ---
155
  **Disclaimers:**
@@ -192,5 +219,5 @@ if __name__ == "__main__":
192
 
193
  print("-"*(60 + len(" App Starting ")) + "\n")
194
 
195
- print("Launching Gradio Interface for Basic Agent Evaluation...")
196
  demo.launch(debug=True, share=False)
 
3
  import requests
4
  import inspect
5
  import pandas as pd
6
+ from agent import build_jasper, get_langfuse_handler
7
+ from langchain_core.messages import HumanMessage
8
 
9
  # (Keep Constants as is)
10
  # --- Constants ---
11
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
 
13
+ # --- Jasper Agent Definition ---
14
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
15
+ class JasperAgent:
16
  def __init__(self):
17
+ print("JasperAgent initialized.")
18
+ self.jasper = build_jasper()
19
+ self.langfuse_handler = get_langfuse_handler()
20
+
21
+ def __call__(self, question: str, task_id: str = None) -> str:
22
+ print(f"Agent received question: {question}.")
23
+ try:
24
+ messages = [HumanMessage(content=question)]
25
+
26
+ # Add Langfuse tracing metadata
27
+ config = {
28
+ "callbacks": [self.langfuse_handler],
29
+ "metadata": {
30
+ "trace_name": f"Evaluation_Task_{task_id}" if task_id else "Agent_Query",
31
+ "user_id": "evaluation-user",
32
+ "session_id": "evaluation-session",
33
+ "task_id": task_id,
34
+ "question_preview": question
35
+ }
36
+ }
37
+
38
+ response = self.jasper.invoke({"messages": messages}, config=config)
39
+ answer = response['messages'][-1].content
40
+ print(f"Agent returning answer: {answer}.")
41
+ return answer
42
+ except Exception as e:
43
+ print(f"Error in agent processing: {e}")
44
+ return f"Error processing question: {str(e)}"
45
 
46
  def run_and_submit_all( profile: gr.OAuthProfile | None):
47
  """
48
+ Fetches all questions, runs the JasperAgent on them, submits all answers,
49
  and displays the results.
50
  """
51
  # --- Determine HF Space Runtime URL and Repo URL ---
 
64
 
65
  # 1. Instantiate Agent ( modify this part to create your agent)
66
  try:
67
+ agent = JasperAgent()
68
  except Exception as e:
69
  print(f"Error instantiating agent: {e}")
70
  return f"Error initializing agent: {e}", None
 
104
  print(f"Skipping item with missing task_id or question: {item}")
105
  continue
106
  try:
107
+ # Pass task_id for better tracing
108
+ submitted_answer = agent(question_text, task_id=task_id)
109
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
110
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
111
  except Exception as e:
 
132
  f"User: {result_data.get('username')}\n"
133
  f"Overall Score: {result_data.get('score', 'N/A')}% "
134
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
135
+ f"Message: {result_data.get('message', 'No message received.')}\n"
136
+ f"📊 View detailed traces in your Langfuse dashboard"
137
  )
138
  print("Submission successful.")
139
  results_df = pd.DataFrame(results_log)
 
168
 
169
  # --- Build Gradio Interface using Blocks ---
170
  with gr.Blocks() as demo:
171
+ gr.Markdown("# Jasper Agent Evaluation Runner")
172
  gr.Markdown(
173
  """
174
  **Instructions:**
 
176
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
177
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
178
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
179
+ 4. **Langfuse Tracing**: All agent operations are traced with Langfuse for detailed analysis and debugging.
180
 
181
  ---
182
  **Disclaimers:**
 
219
 
220
  print("-"*(60 + len(" App Starting ")) + "\n")
221
 
222
+ print("Launching Gradio Interface for Jasper Agent Evaluation...")
223
  demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -1,2 +1,9 @@
1
  gradio
2
- requests
 
 
 
 
 
 
 
 
1
  gradio
2
+ requests
3
+ langchain-community
4
+ langchain-huggingface
5
+ langgraph
6
+ langfuse
7
+ langchain-openai
8
+ youtube-transcript-api
9
+ pytube