Skip to content

Commit 074d4cb

Browse files
committed
Initial deployment commit
1 parent 7200ac1 commit 074d4cb

File tree

1,801 files changed

+2783410
-4377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,801 files changed

+2783410
-4377
lines changed

.DS_Store

2 KB
Binary file not shown.

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ out/
66
!/broadcast
77
/broadcast/*/31337/
88
/broadcast/**/dry-run/
9-
9+
/client/lib/smartContractFunctions.sol
1010
# Docs
1111
docs/
1212

1313
# Dotenv file
1414
.env
1515
PRODUCT.md
16-
ai_trader_npc_fastapi/GEMINI.md
16+
ai_trader_npc_fastapi/GEMINI.md
17+
18+
ai_trader_npc_fastapi/test_buy_event.py

ai_trader_npc_fastapi/Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:$PORT

ai_trader_npc_fastapi/api/routes_ai.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

ai_trader_npc_fastapi/api/routes_products.py

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
import os
22
from dotenv import load_dotenv
3-
from eth_account import Account
43

54
load_dotenv()
65

76
RPC_URL = os.getenv("RPC_URL")
8-
WSS_RPC_URL = os.getenv("WSS_RPC_URL") # For event listening
7+
WSS_RPC_URL = os.getenv("WSS_RPC_URL")
98
CONTRACT_ADDRESS = os.getenv("CONTRACT_ADDRESS")
10-
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
11-
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
12-
13-
# Derive owner address from private key
14-
if PRIVATE_KEY:
15-
OWNER_ADDRESS = Account.from_key(PRIVATE_KEY).address
16-
else:
17-
OWNER_ADDRESS = None
9+
AI_PRIVATE_KEY = os.getenv("AI_PRIVATE_KEY")
10+
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
11+
OWNER_ADDRESS = os.getenv("AI_WALLET")

ai_trader_npc_fastapi/main.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
11
import asyncio
22
import threading
33
from fastapi import FastAPI
4-
from api.routes_products import router as products_router
5-
from api.routes_ai import router as ai_router
64
from services.event_listener import start_event_listener
75

86
app = FastAPI(title="AI Trader NPC API", version="1.0")
97

108
def run_event_listener():
11-
"""Helper function to run the asyncio event listener in a new loop."""
129
asyncio.run(start_event_listener())
1310

1411
@app.on_event("startup")
1512
async def startup_event():
16-
"""
17-
On startup, run the event listener in a separate thread.
18-
"""
1913
print("Starting background event listener thread...")
2014
thread = threading.Thread(target=run_event_listener, daemon=True)
2115
thread.start()
2216

23-
app.include_router(products_router, prefix="/api/items", tags=["Items"])
24-
app.include_router(ai_router, prefix="/api/ai", tags=["AI"])
25-
2617
@app.get("/")
2718
def root():
2819
return {"message": "AI Trader NPC Backend is running"}

ai_trader_npc_fastapi/requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ fastapi
22
uvicorn
33
web3
44
python-dotenv
5-
openai
6-
eth_account
5+
google-generativeai
6+
eth_account
7+
gunicorn

ai_trader_npc_fastapi/services/ai_pricing.py

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
11
import json
2-
from openai import OpenAI
3-
from core.config import OPENAI_API_KEY
2+
import google.generativeai as genai
3+
from core.config import GEMINI_API_KEY
44

5-
client = OpenAI(api_key=OPENAI_API_KEY)
5+
genai.configure(api_key=GEMINI_API_KEY)
66

77
def calculate_price_deterministically(base_price, demand_factor, supply_factor):
88
"""
99
Calculates a new price using a deterministic formula based on market factors.
1010
This function is fast, predictable, and controllable.
1111
"""
1212
# --- Tunable Weights ---
13-
# These can be adjusted to change the trader's behavior.
14-
demand_weight = 0.05 # 5% price change per point of demand.
15-
supply_weight = 0.04 # 4% price change per point of supply.
13+
demand_weight = 0.05
14+
supply_weight = 0.04
1615

17-
# --- Pricing Formula ---
1816
demand_adjustment = 1.0 + (demand_factor * demand_weight)
1917
# We use a negative supply_factor to represent supply pressure
2018
supply_adjustment = 1.0 - (supply_factor * supply_weight)
21-
2219
new_price = base_price * demand_adjustment * supply_adjustment
23-
24-
# Ensure price is at least 1
2520
return max(1, int(new_price))
2621

2722

2823
async def get_ai_market_factors(item_name, demand_index, supply):
2924
"""
30-
Uses the LLM to analyze market conditions and return structured factors.
25+
the LLM to analyze market conditions and return structured factors.
3126
"""
27+
model = genai.GenerativeModel('models/gemini-flash-latest')
28+
3229
system_prompt = (
3330
"You are a master trader in a fantasy world. Your goal is to analyze market data "
3431
"and provide key factors for a pricing model. Respond only with a valid JSON object."
@@ -44,15 +41,11 @@ async def get_ai_market_factors(item_name, demand_index, supply):
4441
)
4542

4643
try:
47-
response = client.chat.completions.create(
48-
model="gpt-4o-mini",
49-
messages=[
50-
{"role": "system", "content": system_prompt},
51-
{"role": "user", "content": user_prompt}
52-
],
53-
response_format={"type": "json_object"}
44+
response = await model.generate_content_async(
45+
[system_prompt, user_prompt],
46+
generation_config={"response_mime_type": "application/json"}
5447
)
55-
factors = json.loads(response.choices[0].message.content)
48+
factors = json.loads(response.text)
5649
print(f"AI market analysis for {item_name}: {factors}")
5750
return factors
5851

@@ -63,18 +56,15 @@ async def get_ai_market_factors(item_name, demand_index, supply):
6356

6457
async def get_hybrid_price_suggestion(item_name, base_price, demand_index, supply):
6558
"""
66-
Orchestrates the hybrid pricing model.
59+
Orchestrates our hybrid pricing model.
6760
1. Gets market factors from the AI.
6861
2. Calculates the final price using a deterministic formula.
6962
"""
70-
# Step 1: Get market analysis from the LLM
7163
factors = await get_ai_market_factors(item_name, demand_index, supply)
72-
7364
if not factors or 'demand_factor' not in factors or 'supply_factor' not in factors:
7465
print("Could not retrieve valid market factors from AI. Aborting price change.")
7566
return None
76-
77-
# Step 2: Calculate the final price deterministically
67+
7868
new_price = calculate_price_deterministically(
7969
base_price=base_price,
8070
demand_factor=factors['demand_factor'],

ai_trader_npc_fastapi/services/event_listener.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,13 @@ async def handle_event(event):
2929
demand_signals[item_address] = max(0, min(10, demand_signals[item_address]))
3030
demand_index = demand_signals[item_address]
3131

32-
# On-chain data
3332
item_details = await get_item_details(item_address)
3433
if not item_details:
3534
return
3635

3736
current_price = item_details["price"]
3837
current_inventory = item_details["inventory"]
3938

40-
# AI suggestion
4139
new_price = await get_hybrid_price_suggestion(
4240
item_name=item_address,
4341
base_price=current_price,
@@ -65,17 +63,13 @@ async def start_event_listener():
6563
async for w3 in AsyncWeb3(WebSocketProvider(WSS_RPC_URL), modules={"eth": (AsyncEth,)}):
6664
print("Connected to WebSocket provider!")
6765

68-
# Load contract ABI
6966
with open("../abi/AITrader.json") as f:
7067
contract_abi = json.load(f)
7168

7269
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=contract_abi)
73-
74-
# Create event filters
7570
bought_filter = await contract.events.ItemBought.create_filter(from_block="latest")
7671
sold_filter = await contract.events.ItemSold.create_filter(from_block="latest")
7772
print("Event filters created.")
78-
# Poll events
7973
while True:
8074
for event in await bought_filter.get_new_entries():
8175
await handle_event(event)

0 commit comments

Comments
 (0)