From 8765b03f74394b305da5f63a76ba44ef10cbd3ab Mon Sep 17 00:00:00 2001 From: DevDendrite Date: Fri, 17 Oct 2025 15:01:02 +0200 Subject: [PATCH 1/4] generation of new questions periodically --- quant/utils/questioner.py | 80 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 quant/utils/questioner.py diff --git a/quant/utils/questioner.py b/quant/utils/questioner.py new file mode 100644 index 0000000..5c4b3bf --- /dev/null +++ b/quant/utils/questioner.py @@ -0,0 +1,80 @@ +from datetime import timedelta, datetime +from typing import Optional +import random +import json + +import google.genai as genai +from pydantic import BaseModel, Field +import bittensor as bt + + +GENERATION_PROMPT = """Create a list of {question_count} questions that sound like they're being asked by a real person with varying levels of knowledge. The questions should be about common crypto topics. Some should be professionally formatted and others lazy (e.g., no capitalization, missing punctuation). The questions should cover the following topics, with an example for each: +* Portfolio Analytics: (e.g., "how can i evaluate my portfolio risk") +* Yield & Earning: (e.g., "what's the best way to earn yield on my ETH") +* Trading & Popularity: (e.g., "what are the trading tokens on solana?") +* Investment Advice: (e.g., "should i buy BONK?") +* Token Risk & Security: (e.g., "who are the top holders of pepe?")""" + + +class Questioner: + + def __init__( + self, + api_key: str, + question_lifetime: timedelta = timedelta(days=7), + initial_questions: Optional[list[str]] = None, + question_count: int = 42, + llm_model: str = "gemini-2.5-flash-lite", + temperature: float = 1.0, + ): + self.question_lifetime = question_lifetime + self.questions: list[str] = initial_questions or [] + self.last_question_update = datetime.now() + + self.genai_client = genai.Client(api_key=api_key) + self.llm_model: str = llm_model + self.question_count: int = question_count + self.temperature: float = temperature + + def choose_question(self) -> str: + self.maybe_update_questions() + return random.choice(self.questions) + + def maybe_update_questions(self): + if not self.questions or self.is_update_time(): + self.questions = self.generate_exactly_n_questions(n=self.question_count) + self.last_question_update = datetime.now() + + def is_update_time(self) -> bool: + return datetime.now() - self.last_question_update > self.question_lifetime + + def generate_exactly_n_questions(self, n: int) -> list[str]: + new_questions = [] + while len(new_questions) < n: + qs = self.generate_about_n_questions(n=n - len(new_questions)) + print(f"{len(qs) = }") + new_questions.extend(qs) + return new_questions[:n] + + def generate_about_n_questions(self, n: int) -> list[str]: + class Questions(BaseModel): + questions: list[str] = Field(..., description="List of crypto questions") + + prompt = GENERATION_PROMPT.format(question_count=n) + + response = self.genai_client.models.generate_content( + model=self.llm_model, + contents=prompt, + config=genai.types.GenerateContentConfig( + response_mime_type="application/json", + response_schema=Questions, + temperature=self.temperature, + ), + ) + + if response_text := response.text: + data = json.loads(response_text) + return data["questions"] + else: + bt.logging.warning("No questions were generated!") + return [] From e1888d541bdac4545f0b1b535acccf02cc7463a9 Mon Sep 17 00:00:00 2001 From: DevDendrite Date: Fri, 17 Oct 2025 15:02:45 +0200 Subject: [PATCH 2/4] use question generation in forward --- quant/validator/forward.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/quant/validator/forward.py b/quant/validator/forward.py index 9421a4f..37add07 100644 --- a/quant/validator/forward.py +++ b/quant/validator/forward.py @@ -17,13 +17,11 @@ import os import time -import random import bittensor as bt from quant.protocol import QuantQuery, QuantSynapse from quant.validator.reward import get_rewards from quant.utils.uids import get_random_uids -from quant.utils.questions import questions async def forward(self): @@ -44,9 +42,12 @@ async def forward(self): if not wallet_address: bt.logging.error("SOLANA_WALLET environment variable is not set. Using a default value.") wallet_address = "5HHSqMvTCvgtzdqFb5BbtYjB8cEiJjf8UZ6p5rQczagL" + + question = self.questioner.choose_question() + bt.logging.info(f"Choosen question: '{question}'") query = QuantQuery( - query=random.choice(questions), + query=question, userID=wallet_address, metadata={ "Create_Proof": "True", From 9dc473db75ee46831ca64071d1af811dffbce649 Mon Sep 17 00:00:00 2001 From: DevDendrite Date: Fri, 17 Oct 2025 15:04:19 +0200 Subject: [PATCH 3/4] initialize question generation with validator initialization --- neurons/validator.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/neurons/validator.py b/neurons/validator.py index 7e36957..3417844 100644 --- a/neurons/validator.py +++ b/neurons/validator.py @@ -17,7 +17,7 @@ import time -import sys +import os # Bittensor import bittensor as bt @@ -31,6 +31,8 @@ # Import the shared Quant agent server module from neurons import quant_agent_server +from quant.utils.questioner import Questioner + class Validator(BaseValidatorNeuron): """ Your validator neuron class. You should use this class to define your validator's behavior. In particular, you should replace the forward function with your own logic. @@ -46,6 +48,11 @@ def __init__(self, config=None): bt.logging.info("load_state()") self.load_state() + api_key = os.getenv("GEMINI_API_KEY", "") + if not api_key: + bt.logging.warning("No GEMINI_API_KEY found in environment variables!") + + self.questioner = Questioner(api_key=api_key) # TODO(developer): Anything specific to your use case you can do here async def forward(self): From ebcfaa38f8a4e077ec81ae6b58d9e7c435f57031 Mon Sep 17 00:00:00 2001 From: DevDendrite Date: Fri, 17 Oct 2025 15:05:21 +0200 Subject: [PATCH 4/4] validators now require Gemini API key for generating questions --- .env.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.example b/.env.example index 6ed4aef..26425e0 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,9 @@ export VALIDATOR_CADENCE='500' # Solana wallet for sample queries, should have at least 0.1 SOL export SOLANA_WALLET='5HHSqMvTCvgtzdqFb5BbtYjB8cEiJjf8UZ6p5rQczagL' +# Gemini API key for question generation +export GEMINI_API_KEY='' + # MINER CONFIGS FOR BITQUANT AGENT # REPO: https://github.com/OpenGradient/BitQuant-Subnet