omsandeepatil commited on
Commit
92aa666
·
verified ·
1 Parent(s): 387acbb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -102
app.py CHANGED
@@ -3,10 +3,10 @@ Blockchain Wallet Analyzer - A tool for analyzing Ethereum wallet contents and N
3
 
4
  This module provides a complete implementation of a blockchain wallet analysis tool
5
  with a Gradio web interface. It includes wallet analysis, NFT tracking, and
6
- interactive chat capabilities using the OpenAI API.
7
 
8
  Author: Claude
9
- Date: January 2025
10
  """
11
 
12
  from __future__ import annotations
@@ -25,15 +25,19 @@ from enum import Enum
25
  from pathlib import Path
26
 
27
  import aiohttp
28
- import openai
29
  import gradio as gr
30
  from tenacity import retry, stop_after_attempt, wait_exponential
 
31
 
32
  # Type variables
33
  T = TypeVar('T')
34
  WalletData = Dict[str, Any]
35
  ChatHistory = List[Tuple[str, str]]
36
 
 
 
 
 
37
  # Configure logging
38
  logging.basicConfig(
39
  level=logging.INFO,
@@ -77,7 +81,7 @@ class Config:
77
  ETHEREUM_ADDRESS_REGEX: str = r"0x[a-fA-F0-9]{40}"
78
  RATE_LIMIT_DELAY: float = 0.2 # 5 requests per second max for free tier
79
  MAX_RETRIES: int = 3
80
- OPENAI_MODEL: str = "gpt-4o-mini" # Updated to correct model name
81
  MAX_TOKENS: int = 4000
82
  TEMPERATURE: float = 0.7
83
  HISTORY_LIMIT: int = 5
@@ -96,9 +100,9 @@ class Config:
96
  class WalletAnalyzer:
97
  """Analyzes Ethereum wallet contents using Etherscan API."""
98
 
99
- def __init__(self, api_key: str):
100
  """Initialize the analyzer with API key."""
101
- self.api_key = api_key
102
  self.base_url = Config.ETHERSCAN_BASE_URL
103
  self.last_request_time = 0
104
  self.session: Optional[aiohttp.ClientSession] = None
@@ -276,38 +280,12 @@ class WalletAnalyzer:
276
 
277
 
278
  class ChatInterface:
279
- """Handles chat interaction using OpenAI API."""
280
 
281
- def __init__(self, openai_key: str, etherscan_key: str):
282
- """Initialize chat interface with API keys."""
283
- self.openai_key = openai_key
284
- self.etherscan_key = etherscan_key
285
  self.context: Dict[str, Any] = {}
286
- openai.api_key = openai_key
287
-
288
- @staticmethod
289
- def _validate_api_keys(openai_key: str, etherscan_key: str) -> Tuple[bool, str]:
290
- """Validate both API keys."""
291
- try:
292
- # Validate OpenAI key
293
- client = openai.OpenAI(api_key=openai_key)
294
- client.chat.completions.create(
295
- model=Config.OPENAI_MODEL,
296
- messages=[{"role": "user", "content": "test"}],
297
- max_tokens=1
298
- )
299
-
300
- # Validate Etherscan key
301
- async def validate_etherscan():
302
- async with WalletAnalyzer(etherscan_key) as analyzer:
303
- params = {"module": "stats", "action": "ethsupply"}
304
- await analyzer._fetch_data(params)
305
-
306
- asyncio.run(validate_etherscan())
307
- return True, "Both API keys are valid! 🎉"
308
-
309
- except Exception as e:
310
- return False, f"API key validation failed: {str(e)}"
311
 
312
  def _format_context_message(self) -> str:
313
  """Format wallet data as context message."""
@@ -356,7 +334,7 @@ class ChatInterface:
356
  if match:
357
  try:
358
  address = match.group(0)
359
- async with WalletAnalyzer(self.etherscan_key) as analyzer:
360
  wallet_data = await analyzer.get_portfolio_data(address)
361
  self.context[address] = wallet_data
362
 
@@ -383,12 +361,12 @@ class ChatInterface:
383
  history.append((message, error_message))
384
  return history, self.context, ""
385
 
386
- # Generate response using OpenAI
387
  try:
388
  # Format context message
389
  context_msg = self._format_context_message()
390
 
391
- # Convert history to OpenAI format
392
  chat_history = []
393
  for user_msg, assistant_msg in history[-Config.HISTORY_LIMIT:]:
394
  chat_history.extend([
@@ -396,10 +374,9 @@ class ChatInterface:
396
  {"role": "assistant", "content": assistant_msg}
397
  ])
398
 
399
- # Create OpenAI client and generate response
400
- client = openai.OpenAI(api_key=self.openai_key)
401
- response = client.chat.completions.create(
402
- model=Config.OPENAI_MODEL,
403
  messages=[
404
  {"role": "system", "content": Config.SYSTEM_PROMPT},
405
  {"role": "system", "content": context_msg},
@@ -431,7 +408,7 @@ class GradioInterface:
431
 
432
  def __init__(self):
433
  """Initialize Gradio interface."""
434
- self.chat_interface: Optional[ChatInterface] = None
435
  self.demo = self._create_interface()
436
 
437
  def _create_interface(self) -> gr.Blocks:
@@ -441,32 +418,10 @@ class GradioInterface:
441
  # 🐕 LOSS DOG: Blockchain Wallet Analyzer
442
 
443
  Welcome to LOSS DOG - Your friendly blockchain analysis companion!
444
- - Enter your API keys below to get started
445
  - Input an Ethereum wallet address to analyze
446
  - Chat about your wallet contents with context!
447
  """)
448
 
449
- # API Keys Section
450
- with gr.Row():
451
- with gr.Column():
452
- openai_key = gr.Textbox(
453
- label="OpenAI API Key",
454
- type="password",
455
- placeholder="Enter your OpenAI API key..."
456
- )
457
- with gr.Column():
458
- etherscan_key = gr.Textbox(
459
- label="Etherscan API Key",
460
- type="password",
461
- placeholder="Enter your Etherscan API key..."
462
- )
463
-
464
- validation_status = gr.Textbox(
465
- label="Validation Status",
466
- interactive=False
467
- )
468
- validate_btn = gr.Button("Validate API Keys", variant="primary")
469
-
470
  # Main Interface
471
  with gr.Row():
472
  # Chat Area (Left Side)
@@ -493,37 +448,12 @@ class GradioInterface:
493
  )
494
  clear_btn = gr.Button("Clear Context", variant="secondary")
495
 
496
- # Initial States
497
- msg_input.interactive = False
498
- send_btn.interactive = False
499
-
500
- # Event Handlers
501
- def validate_keys(openai_k: str, etherscan_k: str) -> Tuple[str, gr.update, gr.update]:
502
- """Validate API keys and initialize chat interface."""
503
- is_valid, message = ChatInterface._validate_api_keys(openai_k, etherscan_k)
504
-
505
- if is_valid:
506
- self.chat_interface = ChatInterface(openai_k, etherscan_k)
507
- return (
508
- "✅ API keys validated! You can start chatting now.",
509
- gr.update(interactive=True),
510
- gr.update(interactive=True)
511
- )
512
- return (
513
- f"❌ Validation failed: {message}",
514
- gr.update(interactive=False),
515
- gr.update(interactive=False)
516
- )
517
-
518
  async def handle_message(
519
  message: str,
520
  chat_history: List[Tuple[str, str]],
521
  context: Dict[str, Any]
522
  ) -> Tuple[List[Tuple[str, str]], Dict[str, Any]]:
523
  """Handle incoming messages."""
524
- if not self.chat_interface:
525
- return [], {}
526
-
527
  try:
528
  history, new_context, _ = await self.chat_interface.process_message(
529
  message,
@@ -539,19 +469,12 @@ class GradioInterface:
539
  return chat_history, context
540
 
541
  # Connect Event Handlers
542
- validate_btn.click(
543
- fn=validate_keys,
544
- inputs=[openai_key, etherscan_key],
545
- outputs=[validation_status, msg_input, send_btn]
546
  )
547
 
548
- if self.chat_interface:
549
- clear_btn.click(
550
- fn=self.chat_interface.clear_context,
551
- inputs=[],
552
- outputs=[wallet_context, chatbot]
553
- )
554
-
555
  # Message Handling
556
  msg_input.submit(
557
  fn=handle_message,
 
3
 
4
  This module provides a complete implementation of a blockchain wallet analysis tool
5
  with a Gradio web interface. It includes wallet analysis, NFT tracking, and
6
+ interactive chat capabilities using the Groq API.
7
 
8
  Author: Claude
9
+ Date: March 2025
10
  """
11
 
12
  from __future__ import annotations
 
25
  from pathlib import Path
26
 
27
  import aiohttp
 
28
  import gradio as gr
29
  from tenacity import retry, stop_after_attempt, wait_exponential
30
+ import groq
31
 
32
  # Type variables
33
  T = TypeVar('T')
34
  WalletData = Dict[str, Any]
35
  ChatHistory = List[Tuple[str, str]]
36
 
37
+ # API Keys - Define as constants in the script
38
+ GROQ_API_KEY = "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"
39
+ ETHERSCAN_API_KEY = "V562U3P76KKEUJ2DV9Q3U2EPDK89T5CKNH"
40
+
41
  # Configure logging
42
  logging.basicConfig(
43
  level=logging.INFO,
 
81
  ETHEREUM_ADDRESS_REGEX: str = r"0x[a-fA-F0-9]{40}"
82
  RATE_LIMIT_DELAY: float = 0.2 # 5 requests per second max for free tier
83
  MAX_RETRIES: int = 3
84
+ GROQ_MODEL: str = "llama3-70b-8192" # Groq's high-performance model
85
  MAX_TOKENS: int = 4000
86
  TEMPERATURE: float = 0.7
87
  HISTORY_LIMIT: int = 5
 
100
  class WalletAnalyzer:
101
  """Analyzes Ethereum wallet contents using Etherscan API."""
102
 
103
+ def __init__(self):
104
  """Initialize the analyzer with API key."""
105
+ self.api_key = ETHERSCAN_API_KEY
106
  self.base_url = Config.ETHERSCAN_BASE_URL
107
  self.last_request_time = 0
108
  self.session: Optional[aiohttp.ClientSession] = None
 
280
 
281
 
282
  class ChatInterface:
283
+ """Handles chat interaction using Groq API."""
284
 
285
+ def __init__(self):
286
+ """Initialize chat interface with Groq client."""
287
+ self.groq_client = groq.Client(api_key=GROQ_API_KEY)
 
288
  self.context: Dict[str, Any] = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  def _format_context_message(self) -> str:
291
  """Format wallet data as context message."""
 
334
  if match:
335
  try:
336
  address = match.group(0)
337
+ async with WalletAnalyzer() as analyzer:
338
  wallet_data = await analyzer.get_portfolio_data(address)
339
  self.context[address] = wallet_data
340
 
 
361
  history.append((message, error_message))
362
  return history, self.context, ""
363
 
364
+ # Generate response using Groq
365
  try:
366
  # Format context message
367
  context_msg = self._format_context_message()
368
 
369
+ # Convert history to Groq format
370
  chat_history = []
371
  for user_msg, assistant_msg in history[-Config.HISTORY_LIMIT:]:
372
  chat_history.extend([
 
374
  {"role": "assistant", "content": assistant_msg}
375
  ])
376
 
377
+ # Generate response using Groq
378
+ response = self.groq_client.chat.completions.create(
379
+ model=Config.GROQ_MODEL,
 
380
  messages=[
381
  {"role": "system", "content": Config.SYSTEM_PROMPT},
382
  {"role": "system", "content": context_msg},
 
408
 
409
  def __init__(self):
410
  """Initialize Gradio interface."""
411
+ self.chat_interface = ChatInterface()
412
  self.demo = self._create_interface()
413
 
414
  def _create_interface(self) -> gr.Blocks:
 
418
  # 🐕 LOSS DOG: Blockchain Wallet Analyzer
419
 
420
  Welcome to LOSS DOG - Your friendly blockchain analysis companion!
 
421
  - Input an Ethereum wallet address to analyze
422
  - Chat about your wallet contents with context!
423
  """)
424
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  # Main Interface
426
  with gr.Row():
427
  # Chat Area (Left Side)
 
448
  )
449
  clear_btn = gr.Button("Clear Context", variant="secondary")
450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  async def handle_message(
452
  message: str,
453
  chat_history: List[Tuple[str, str]],
454
  context: Dict[str, Any]
455
  ) -> Tuple[List[Tuple[str, str]], Dict[str, Any]]:
456
  """Handle incoming messages."""
 
 
 
457
  try:
458
  history, new_context, _ = await self.chat_interface.process_message(
459
  message,
 
469
  return chat_history, context
470
 
471
  # Connect Event Handlers
472
+ clear_btn.click(
473
+ fn=self.chat_interface.clear_context,
474
+ inputs=[],
475
+ outputs=[wallet_context, chatbot]
476
  )
477
 
 
 
 
 
 
 
 
478
  # Message Handling
479
  msg_input.submit(
480
  fn=handle_message,