|
3 | 3 | from typing import List, Optional |
4 | 4 | from xml.dom.minidom import parseString |
5 | 5 |
|
6 | | -from sqlalchemy import and_, select, func, delete, update, or_ |
| 6 | +from sqlalchemy import case, and_, select, func, delete, update, or_ |
7 | 7 | from sqlalchemy import text |
8 | 8 |
|
9 | 9 | from apps.ai_model.embedding import EmbeddingModelCache |
| 10 | +from apps.datasource.embedding.utils import parse_valid_embedding |
10 | 11 | from apps.data_training.models.data_training_model import DataTrainingInfo, DataTraining, DataTrainingInfoResult |
11 | 12 | from apps.datasource.models.datasource import CoreDatasource |
12 | 13 | from apps.system.models.system_model import AssistantModel |
13 | 14 | from apps.template.generate_chart.generator import get_base_data_training_template |
14 | | -from common.core.config import settings |
| 15 | +from common.core.embedding_config import EmbeddingConfig, load_embedding_config |
15 | 16 | from common.core.deps import SessionDep, Trans |
16 | 17 | from common.utils.dict_to_xml import dict_to_xml |
| 18 | +from common.utils.embedding_lifecycle import generate_missing_embeddings |
17 | 19 | from common.utils.embedding_threads import run_save_data_training_embeddings |
18 | 20 |
|
19 | 21 |
|
@@ -266,6 +268,7 @@ def update_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans |
266 | 268 | raise Exception(trans("i18n_data_training.exists_in_db")) |
267 | 269 |
|
268 | 270 | stmt = update(DataTraining).where(and_(DataTraining.id == info.id)).values( |
| 271 | + embedding=case((DataTraining.question.is_distinct_from(info.question.strip()), None), else_=DataTraining.embedding), |
269 | 272 | question=info.question.strip(), |
270 | 273 | description=info.description.strip(), |
271 | 274 | datasource=info.datasource, |
@@ -442,84 +445,46 @@ def enable_training(session: SessionDep, id: int, enabled: bool, trans: Trans, o |
442 | 445 | session.commit() |
443 | 446 |
|
444 | 447 |
|
445 | | -# def run_save_embeddings(ids: List[int]): |
446 | | -# executor.submit(save_embeddings, ids) |
447 | | -# |
448 | | -# |
449 | | -# def fill_empty_embeddings(): |
450 | | -# executor.submit(run_fill_empty_embeddings) |
451 | | - |
452 | | - |
453 | 448 | def run_fill_empty_embeddings(session_maker): |
454 | | - try: |
455 | | - if not settings.EMBEDDING_ENABLED: |
456 | | - return |
457 | | - |
458 | | - session = session_maker() |
459 | | - stmt = select(DataTraining.id).where(and_(DataTraining.embedding.is_(None))) |
460 | | - results = session.execute(stmt).scalars().all() |
461 | | - |
462 | | - save_embeddings(session_maker, results) |
463 | | - except Exception: |
464 | | - traceback.print_exc() |
465 | | - finally: |
466 | | - session_maker.remove() |
| 449 | + return generate_missing_embeddings(session_maker, DataTraining, DataTraining.question) |
467 | 450 |
|
468 | 451 |
|
469 | 452 | def save_embeddings(session_maker, ids: List[int]): |
470 | | - if not settings.EMBEDDING_ENABLED: |
471 | | - return |
472 | | - |
473 | | - if not ids or len(ids) == 0: |
| 453 | + if not ids: |
474 | 454 | return |
475 | | - try: |
476 | | - session = session_maker() |
477 | | - _list = session.query(DataTraining).filter(and_(DataTraining.id.in_(ids))).all() |
478 | | - |
479 | | - _question_list = [item.question for item in _list] |
480 | | - |
481 | | - model = EmbeddingModelCache.get_model() |
482 | | - |
483 | | - results = model.embed_documents(_question_list) |
484 | | - |
485 | | - for index in range(len(results)): |
486 | | - item = results[index] |
487 | | - stmt = update(DataTraining).where(and_(DataTraining.id == _list[index].id)).values(embedding=item) |
488 | | - session.execute(stmt) |
489 | | - session.commit() |
490 | | - |
491 | | - except Exception: |
492 | | - traceback.print_exc() |
493 | | - finally: |
494 | | - session_maker.remove() |
| 455 | + return generate_missing_embeddings( |
| 456 | + session_maker, DataTraining, DataTraining.question, |
| 457 | + DataTraining.id.in_(ids), |
| 458 | + ) |
495 | 459 |
|
496 | 460 |
|
497 | | -embedding_sql = f""" |
| 461 | +embedding_sql = """ |
498 | 462 | SELECT id, datasource, question, similarity |
499 | 463 | FROM |
500 | 464 | (SELECT id, datasource, question, oid, enabled, |
501 | 465 | ( 1 - (embedding <=> :embedding_array) ) AS similarity |
502 | 466 | FROM data_training AS child |
503 | 467 | ) TEMP |
504 | | -WHERE similarity > {settings.EMBEDDING_DATA_TRAINING_SIMILARITY} and oid = :oid and datasource = :datasource and enabled = true |
| 468 | +WHERE similarity > :similarity and oid = :oid and datasource = :datasource and enabled = true |
505 | 469 | ORDER BY similarity DESC |
506 | | -LIMIT {settings.EMBEDDING_DATA_TRAINING_TOP_COUNT} |
| 470 | +LIMIT :top_count |
507 | 471 | """ |
508 | | -embedding_sql_in_advanced_application = f""" |
| 472 | +embedding_sql_in_advanced_application = """ |
509 | 473 | SELECT id, advanced_application, question, similarity |
510 | 474 | FROM |
511 | 475 | (SELECT id, advanced_application, question, oid, enabled, |
512 | 476 | ( 1 - (embedding <=> :embedding_array) ) AS similarity |
513 | 477 | FROM data_training AS child |
514 | 478 | ) TEMP |
515 | | -WHERE similarity > {settings.EMBEDDING_DATA_TRAINING_SIMILARITY} and oid = :oid and advanced_application = :advanced_application and enabled = true |
| 479 | +WHERE similarity > :similarity and oid = :oid and advanced_application = :advanced_application and enabled = true |
516 | 480 | ORDER BY similarity DESC |
517 | | -LIMIT {settings.EMBEDDING_DATA_TRAINING_TOP_COUNT} |
| 481 | +LIMIT :top_count |
518 | 482 | """ |
519 | 483 |
|
520 | 484 |
|
521 | 485 | def select_training_by_question(session: SessionDep, question: str, oid: int, datasource: Optional[int] = None, |
522 | | - advanced_application_id: Optional[int] = None): |
| 486 | + advanced_application_id: Optional[int] = None, *, config: EmbeddingConfig | None = None): |
| 487 | + config = config or load_embedding_config(session) |
523 | 488 | if question.strip() == "": |
524 | 489 | return [] |
525 | 490 |
|
@@ -547,20 +512,20 @@ def select_training_by_question(session: SessionDep, question: str, oid: int, da |
547 | 512 | for row in results: |
548 | 513 | _list.append(DataTraining(id=row.id, question=row.question)) |
549 | 514 |
|
550 | | - if settings.EMBEDDING_ENABLED: |
| 515 | + if config.enabled: |
551 | 516 | with session.begin_nested(): |
552 | 517 | try: |
553 | 518 | model = EmbeddingModelCache.get_model() |
554 | 519 |
|
555 | | - embedding = model.embed_query(question) |
| 520 | + embedding = parse_valid_embedding(model.embed_query(question)) |
556 | 521 |
|
557 | 522 | if advanced_application_id is not None: |
558 | 523 | results = session.execute(text(embedding_sql_in_advanced_application), |
559 | | - {'embedding_array': str(embedding), 'oid': oid, |
| 524 | + {'embedding_array': str(embedding), 'oid': oid, 'similarity': config.data_training_similarity, 'top_count': config.data_training_top_count, |
560 | 525 | 'advanced_application': advanced_application_id}) |
561 | 526 | else: |
562 | 527 | results = session.execute(text(embedding_sql), |
563 | | - {'embedding_array': str(embedding), 'oid': oid, 'datasource': datasource}) |
| 528 | + {'embedding_array': str(embedding), 'oid': oid, 'similarity': config.data_training_similarity, 'top_count': config.data_training_top_count, 'datasource': datasource}) |
564 | 529 |
|
565 | 530 | for row in results: |
566 | 531 | _list.append(DataTraining(id=row.id, question=row.question)) |
@@ -617,12 +582,14 @@ def to_xml_string(_dict: list[dict] | dict, root: str = 'sql-examples') -> str: |
617 | 582 |
|
618 | 583 |
|
619 | 584 | def get_training_template(session: SessionDep, question: str, oid: Optional[int] = 1, datasource: Optional[int] = None, |
620 | | - advanced_application_id: Optional[int] = None) -> tuple[str, list[dict]]: |
| 585 | + advanced_application_id: Optional[int] = None, *, |
| 586 | + config: EmbeddingConfig | None = None) -> tuple[str, list[dict]]: |
| 587 | + config = config or load_embedding_config(session) |
621 | 588 | if not oid: |
622 | 589 | oid = 1 |
623 | 590 | if not datasource and not advanced_application_id: |
624 | 591 | return '', [] |
625 | | - _results = select_training_by_question(session, question, oid, datasource, advanced_application_id) |
| 592 | + _results = select_training_by_question(session, question, oid, datasource, advanced_application_id, config=config) |
626 | 593 | if _results and len(_results) > 0: |
627 | 594 | data_training = to_xml_string(_results) |
628 | 595 | template = get_base_data_training_template().format(data_training=data_training) |
|
0 commit comments