Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lamb-kb-server-stable/backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ FIRECRAWL_API_URL=http://host.docker.internal:3002
# FIRECRAWL_API_URL=https://api.firecrawl.dev
# FIRECRAWL_API_KEY=your-firecrawl-api-key-here

# LangSmith Evaluation Configuration
API_BASE_URL=http://localhost:9099
JWT_TOKEN=your-jwt-token-here
ASSISTANT_ID=1 # your-assistant-id-here
DATASET_NAME=your-dataset-name
EVALUATOR_MODEL=gpt-4.1

# Logging
# LAMB KB webapp-specific log level (falls back to GLOBAL_LOG_LEVEL if unset)
LAMB_KB_LOG_LEVEL=WARNING
134 changes: 134 additions & 0 deletions scripts/langsmith/dbizi_dataset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import os
from pathlib import Path

from dotenv import load_dotenv
from langsmith import Client

# Load environment variables from backend
project_root = Path(__file__).parent.parent.parent
load_dotenv(project_root / "backend" / ".env")

example_inputs = [
(
"¿Cómo inicio el servicio con una bicicleta tanto mecánica como eléctrica?",
"Mediante la app de PBSC. Selecciona la opción 'obtener una bicicleta' dentro del mapa principal, escanea el código QR y espera a que la luz amarilla se vuelva verde para poder retirar tu bicicleta. Fuente: https://www.dbizi.eus/es/preguntas-frecuentes",
),
(
"¿Cómo contacto con atención al cliente si tengo una incidencia o duda?",
"Para contactar con atención al cliente de Dbizi en caso de tener una incidencia o duda, puedes enviar un correo electrónico a mailto:soporte@dbizi.eus explicando lo que te ha ocurrido. Si se trata de una emergencia o de un problema más urgente, es recomendable llamar al 943 060 888, que está dedicado a averías. Fuente: https://www.dbizi.eus/es/preguntas-frecuentes",
),
(
"¿Cómo puedo contactar con Dbizi?",
"Puedes contactar por WhatsApp/Telegram al 648 019 332, teléfono 943 060 888 y correo info@dbizi.eus. Fuente: https://www.dbizi.eus/es/contacto",
),
(
"¿Qué pasa cuando no hay espacio disponible en una estación para devolver la bicicleta?",
"Si quieres dejar una bicicleta y la estación está llena, solicita la ampliación de 10 minutos adicionales sin coste en la app para poder llegar a la estación más próxima con espacio. Fuente: https://www.dbizi.eus/es/preguntas-frecuentes",
),
(
"¿Existen descuentos para familias numerosas o empresas?",
"Sí, hay descuentos del 20% (normal) y 50% (especial) para familias numerosas, y descuentos para empresas a partir del sexto miembro. Fuente: https://www.dbizi.eus/es/tarifas",
),
(
"¿Qué tipos de abonos existen, cuál es su duración y cómo funcionan los precios?",
"Hay abonos ordinarios (individual y grupal, 12 meses) y ocasionales (individual, 30 días). El abono grupal es para 2-5 personas. El abono no incluye viajes, se cobra por uso. Fuente: https://www.dbizi.eus/es/tarifas",
),
(
"¿Qué ocurre si la estación está llena al devolver la bicicleta?",
"Si la estación está llena, el sistema te otorga 10 minutos extra para devolver la bicicleta en la estación más cercana sin coste adicional. Fuente: https://www.dbizi.eus/es/como-funciona",
),
(
"¿En qué ámbito se pueden utilizar las bicicletas del sistema?",
"Las bicicletas del sistema podrán utilizarse única y exclusivamente dentro del término municipal de San Sebastián y deberán ser recogidas y devueltas en las estaciones del sistema. Fuente: https://www.dbizi.eus/es/preguntas-frecuentes",
),
(
"¿A partir de qué edad está permitida la utilización del sistema?",
"El servicio está permitido a mayores de 16 años. Las personas de 16 o 17 años han de aportar la autorización del tutor legal como requisito indispensable para darse de alta. Fuente: https://www.dbizi.eus/es/preguntas-frecuentes",
),
(
"¿Cuál es el horario de atención para contactos?",
"El horario publicado es Lunes-Viernes: 8h-16h. Fuente: https://www.dbizi.eus/es/contacto",
),
(
"¿Cómo puedo inscribirme y quién puede hacerlo?",
"Puedes inscribirte en la web de Dbizi eligiendo la tarifa que prefieras. Los mayores de 16 y menores de 18 años pueden inscribirse con autorización. Fuente: https://www.dbizi.eus/es/como-funciona",
),
(
"¿Qué es Dbizi?",
"Dbizi es el sistema de alquiler de bicicletas del Ayuntamiento de San Sebastián (Donostia). Fuente: https://www.dbizi.eus/es/bienvenido",
),
(
"¿Cuántas bicicletas y estaciones hay?",
"Según la web, hay 317 bicicletas mecánicas, 317 bicicletas eléctricas y 70 estaciones. Fuente: https://www.dbizi.eus/es/bienvenido",
),
(
"¿Dónde puedo consultar el mapa de estaciones y la disponibilidad de bicicletas?",
"En la sección 'Plano y estaciones' de la web puedes ver un mapa interactivo con la ubicación y disponibilidad de bicicletas en tiempo real. Fuente: https://www.dbizi.eus/es/plano-y-estaciones",
),
(
"¿Qué tipos de bicicletas ofrece Dbizi y cómo se desbloquean?",
"Dbizi ofrece bicicletas mecánicas y eléctricas, que se desbloquean utilizando la app PBSC en tu móvil. Fuente: https://www.dbizi.eus/es/como-funciona",
),
]


DATASET_NAME = "dbizi dataset"

DATASET_DESCRIPTION = (
"FAQ de Dbizi con respuestas de referencia para evaluar al asistente."
)


def get_or_create_dataset(client: Client):
"""Retrieves the dataset by name or creates it if it doesn't exist."""
existing = list(client.list_datasets(dataset_name=DATASET_NAME))

if existing:
dataset = existing[0]
print(f"ℹ️ Existing dataset '{DATASET_NAME}' -> {dataset.id}")
return dataset

dataset = client.create_dataset(
dataset_name=DATASET_NAME, description=DATASET_DESCRIPTION
)
print(f"✅ Dataset created '{DATASET_NAME}' -> {dataset.id}")
return dataset


def main() -> None:
client = Client()

dataset = get_or_create_dataset(client)

# Build idempotent examples based on the question
existing_questions = {
example.inputs.get("question")
for example in client.list_examples(dataset_id=dataset.id)
if isinstance(example.inputs, dict)
}

examples = [
{
"inputs": {"question": input_prompt},
"outputs": {"answer": output_answer},
}
for input_prompt, output_answer in example_inputs
if input_prompt not in existing_questions
]

if not examples:
print(
"ℹ️ The dataset already contains all questions, no new examples were added."
)
return

client.create_examples(
dataset_id=dataset.id,
examples=examples,
)

print(f"✅ Done: created {len(examples)} examples in dataset {dataset.id}.")


if __name__ == "__main__":
main()
132 changes: 132 additions & 0 deletions scripts/langsmith/dbizi_dataset_eus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import os
from pathlib import Path

from dotenv import load_dotenv
from langsmith import Client

# Load environment variables from backend
project_root = Path(__file__).parent.parent.parent
load_dotenv(project_root / "backend" / ".env")

example_inputs = [
(
"Nola hasten da zerbitzua bizikleta mekaniko zein elektriko batekin?",
"PBSC-ko app-aren bidez. Hautatu 'bizikleta bat lortu' aukera mapa nagusiaren barruan, eskaneatu QR kodea, eta itxaron argi horia berde jarri arte zure bizikleta hartu ahal izateko. 3 minutu dituzu bizikletaren egoera egiaztatzeko, eta egoera onean ez dagoela uste baduzu, itzuli dezakezu, eta beste bat hartu, 10 minutu itxaron beharrik gabe. Iturria: https://www.dbizi.eus/eu/ohiko-galderak",
),
(
"Nola jarri naiteke harremanetan bezeroarentzako arreta zerbitzuarekin intzidentzia edo zalantza bat badut?",
"Dbiziko bezeroarentzako arreta zerbitzuarekin harremanetan jartzeko, mezu elektroniko bat bidal dezakezu mailto:soporte@dbizi.eus helbidera gertatutakoa azalduz. Larrialdi edo arazo larriagoetan, gomendagarria da 943 060 888 zenbakira deitzea; zenbaki hori aberientzako da. Iturria: https://www.dbizi.eus/eu/ohiko-galderak",
),
(
"Nola jar naiteke harremanetan Dbizirekin?",
"WhatsApp/Telegram bidez 648 019 332 zenbakira, telefono bidez 943 060 888ra eta info@dbizi.eus helbidera idatziz jar zaitezke harremanetan. Iturria: https://www.dbizi.eus/eu/kontaktua",
),
(
"Zer gertatzen da geltoki batean bizikleta itzultzeko lekurik ez dagoenean?",
"Bizikleta bat utzi nahi baduzu eta geltokia beteta badago, eskatu 10 minutu gehiago appean, kosturik gabe, zugandik hurbilen dagoen eta leku libreak dituen geltoki batera iritsi ahal izateko. Horrez gain, zerbitzuak geltoki+ sistema du honako geltoki hauetan: Añorga, Buenavista, Herrera, Txaparrene, Nornahi, Atarizar, Munto, Andoain, Tranbia, Urbia eta Av. Barcelona. Iturria: https://www.dbizi.eus/eu/ohiko-galderak",
),
(
"Familia ugarientzako edo enpresentzako deskontuak badaude?",
"Bai, %20ko (ohikoa) eta %50eko (berezia) deskontuak daude familia ugarientzat, eta deskontuak enpresentzat seigarren kidetik aurrera. Iturria: https://www.dbizi.eus/eu/tarifak",
),
(
"Zer bonu mota daude, zenbat irauten dute eta nola funtzionatzen dute prezioek?",
"Abonu arruntak daude (banakakoa eta taldekoa, 12 hilabete) eta noizbehinkakoak (banakakoa, 30 egun). Taldeko abonoa 2-5 pertsonarentzat da. Bonuak ez ditu bidaiak barne hartzen; erabileraren arabera kobratzen da. Iturria: https://www.dbizi.eus/eu/tarifak",
),
(
"Zer gertatzen da bizikleta itzultzean geltokia beteta badago?",
"Geltokia beteta badago, sistemak 10 minutu gehigarri ematen dizkizu kosturik gabe bizikleta hurbileneko geltokian uzteko. Iturria: https://www.dbizi.eus/eu/nola-erabili",
),
(
"Zein eremutan erabil daitezke sistemako bizikletak?",
"Sistemako bizikletak Donostiako udal mugartean baino ezingo dira erabili, eta sistemaren geltokietan jaso eta itzuli beharko dira. Iturria: https://www.dbizi.eus/eu/ohiko-galderak",
),
(
"Zein adinetik aurrera erabil daiteke sistema?",
"Zerbitzua 16 urtetik gorakoentzat dago baimenduta. 16 edo 17 urteko pertsonek legezko tutorearen baimena aurkeztu/erantsi behar dute, alta emateko ezinbesteko baldintza baita. Iturria: https://www.dbizi.eus/eu/ohiko-galderak",
),
(
"Zein da harremanetarako arreta ordutegia?",
"Argitaratutako ordutegia astelehenetik ostiralera 8:00etatik 16:00etara da. Iturria: https://www.dbizi.eus/eu/kontaktua",
),
(
"Nola eman dezaket izena eta nork egin dezake?",
"Dbiziren webgunean eman dezakezu izena aukeratzen duzun tarifa hautatuz. 16 urtetik gorako eta 18 urtetik beherako pertsonek baimenarekin eman dezakete izena. Iturria: https://www.dbizi.eus/eu/nola-erabili",
),
(
"Zer da Dbizi?",
"Dbizi Donostiako Udalaren bizikleta alokairu sistema da. Iturria: https://www.dbizi.eus/eu/ongi-etorri",
),
(
"Zenbat bizikleta eta geltoki daude?",
"Webguneak dioenez, 317 bizikleta mekaniko, 317 bizikleta elektriko eta 70 geltoki daude. Iturria: https://www.dbizi.eus/eu/ongi-etorri",
),
(
"Non kontsulta dezaket geltokien mapa eta bizikleten erabilgarritasuna?",
"Webguneko 'Mapa eta geltokiak' atalean mapa interaktibo bat ikus dezakezu bizikleten kokapena eta erabilgarritasuna denbora errealean kontsultatzeko. Iturria: https://www.dbizi.eus/eu/mapa-eta-geltokiak",
),
(
"Zer motatako bizikletak eskaintzen ditu Dbizik eta nola desblokeatzen dira?",
"Dbizik bizikleta mekanikoak eta elektrikoak eskaintzen ditu; mugikorrean PBSC aplikazioa erabiliz desblokeatzen dira. Iturria: https://www.dbizi.eus/eu/nola-erabili",
),
]

DATASET_NAME = "dbizi dataset eus"
DATASET_DESCRIPTION = (
"Dbiziren maiz egiten diren galderak erantzun erreferentedunekin, laguntzailea ebaluatzeko."
)


def get_or_create_dataset(client: Client):
"""Retrieves the dataset by name or creates it if it doesn't exist."""
existing = list(client.list_datasets(dataset_name=DATASET_NAME))

if existing:
dataset = existing[0]
print(f"ℹ️ Existing dataset '{DATASET_NAME}' -> {dataset.id}")
return dataset

dataset = client.create_dataset(
dataset_name=DATASET_NAME, description=DATASET_DESCRIPTION
)
print(f"✅ Dataset created '{DATASET_NAME}' -> {dataset.id}")
return dataset


def main() -> None:
client = Client()

dataset = get_or_create_dataset(client)

# Build idempotent examples based on the question
existing_questions = {
example.inputs.get("question")
for example in client.list_examples(dataset_id=dataset.id)
if isinstance(example.inputs, dict)
}

examples = [
{
"inputs": {"question": input_prompt},
"outputs": {"answer": output_answer},
}
for input_prompt, output_answer in example_inputs
if input_prompt not in existing_questions
]

if not examples:
print(
"ℹ️ The dataset already contains all questions, no new examples were added."
)
return

client.create_examples(
dataset_id=dataset.id,
examples=examples,
)

print(f"✅ Done: created {len(examples)} examples in dataset {dataset.id}.")


if __name__ == "__main__":
main()
Loading