-
Notifications
You must be signed in to change notification settings - Fork 82
feat(llm): property embedding #240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
74cf3c5
e9941ad
d2e4e2e
c5ec3ea
12221c9
8343d3c
0036b2c
173b9b2
c9ef9ed
c933c58
263758b
8a0e6cd
a60887d
43cdcae
b4f1a51
142a44e
9f245a0
87cb1cf
961f582
4cbb47a
36116e6
5db4e0c
bf19a84
026c65c
f2ee374
0e98879
a3b864f
ac7e137
8ace5a8
a9f92c4
18744d2
89b2d47
f14087a
ef37855
c24d210
f1fdbdb
2953dbc
cf279f5
182ecba
b7e7425
52c40cb
10e76cd
923502a
739479a
9acaa96
86e6098
b27d925
765e93f
b5f31ff
50ec338
7d9d67c
c918e73
7b7260a
3754211
7a2cf2b
7b3e5e2
cb31b35
9778c37
cf6d2e4
eb5e9f1
e75f68f
4aa1a4d
7b7c6d2
31bf971
a0e460c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,20 +15,21 @@ | |
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| from typing import Optional, Literal | ||
|
|
||
| from typing import Optional, Literal, List | ||
| from enum import Enum | ||
| from fastapi import Query | ||
| from pydantic import BaseModel | ||
|
|
||
| from hugegraph_llm.config import prompt | ||
|
|
||
| from hugegraph_llm.config import huge_settings | ||
|
|
||
| class GraphConfigRequest(BaseModel): | ||
| url: str = Query('127.0.0.1:8080', description="hugegraph client url.") | ||
| name: str = Query('hugegraph', description="hugegraph client name.") | ||
| user: str = Query('', description="hugegraph client user.") | ||
| pwd: str = Query('', description="hugegraph client pwd.") | ||
| graph: str = Query('hugegraph', description="hugegraph client name.") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Evidence: the public graph config model changed |
||
| user: Optional[str] = Query('', description="hugegraph client user.") | ||
| pwd: Optional[str] = Query('', description="hugegraph client pwd.") | ||
| gs: str = None | ||
| token: Optional[str] = Query('', description="hugegraph client token.") | ||
|
|
||
|
|
||
| class RAGRequest(BaseModel): | ||
|
|
@@ -116,3 +117,31 @@ class RerankerConfigRequest(BaseModel): | |
| class LogStreamRequest(BaseModel): | ||
| admin_token: Optional[str] = None | ||
| log_file: Optional[str] = "llm-server.log" | ||
|
|
||
| class GremlinOutputType(str, Enum): | ||
| MATCH_RESULT = "match_result" | ||
| TEMPLATE_GREMLIN = "template_gremlin" | ||
| RAW_GREMLIN = "raw_gremlin" | ||
| TEMPLATE_EXECUTION_RESULT = "template_execution_result" | ||
| RAW_EXECUTION_RESULT = "raw_execution_result" | ||
|
|
||
| class GremlinGenerateRequest(BaseModel): | ||
| query: str | ||
| example_num: Optional[int] = Query( | ||
| 0, | ||
| description="Number of Gremlin templates to use.(0 means no templates)" | ||
| ) | ||
| gremlin_prompt: Optional[str] = Query( | ||
| prompt.gremlin_generate_prompt, | ||
| description="Prompt for the Text2Gremlin query.", | ||
| ) | ||
| client_config: Optional[GraphConfigRequest] = Query(None, description="hugegraph server config.") | ||
| output_types: Optional[List[GremlinOutputType]] = Query( | ||
| default=[GremlinOutputType.TEMPLATE_GREMLIN], | ||
| description=""" | ||
| a list can contain "match_result","template_gremlin", | ||
| "raw_gremlin","template_execution_result","raw_execution_result" | ||
| You can specify which type of result do you need. Empty means all types. | ||
| """ | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ | |
| LLMConfigRequest, | ||
| RerankerConfigRequest, | ||
| GraphRAGRequest, | ||
| GremlinGenerateRequest, | ||
| ) | ||
| from hugegraph_llm.config import huge_settings | ||
| from hugegraph_llm.api.models.rag_response import RAGResponse | ||
|
|
@@ -41,6 +42,7 @@ def rag_http_api( | |
| apply_llm_conf, | ||
| apply_embedding_conf, | ||
| apply_reranker_conf, | ||
| gremlin_generate_selective_func, | ||
| ): | ||
| @router.post("/rag", status_code=status.HTTP_200_OK) | ||
| def rag_answer_api(req: RAGRequest): | ||
|
|
@@ -79,10 +81,11 @@ def rag_answer_api(req: RAGRequest): | |
| def set_graph_config(req): | ||
| if req.client_config: | ||
| huge_settings.graph_url = req.client_config.url | ||
| huge_settings.graph_name = req.client_config.name | ||
| huge_settings.graph_name = req.client_config.graph | ||
| huge_settings.graph_user = req.client_config.user | ||
| huge_settings.graph_pwd = req.client_config.pwd | ||
| huge_settings.graph_space = req.client_config.gs | ||
| huge_settings.graph_token = req.client_config.token | ||
|
|
||
| @router.post("/rag/graph", status_code=status.HTTP_200_OK) | ||
| def graph_rag_recall_api(req: GraphRAGRequest): | ||
|
|
@@ -139,7 +142,7 @@ def graph_rag_recall_api(req: GraphRAGRequest): | |
| @router.post("/config/graph", status_code=status.HTTP_201_CREATED) | ||
| def graph_config_api(req: GraphConfigRequest): | ||
| # Accept status code | ||
| res = apply_graph_conf(req.url, req.name, req.user, req.pwd, req.gs, origin_call="http") | ||
| res = apply_graph_conf(req.url, req.graph, req.user, req.pwd, req.gs, origin_call="http") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Evidence: |
||
| return generate_response(RAGResponse(status_code=res, message="Missing Value")) | ||
|
|
||
| # TODO: restructure the implement of llm to three types, like "/config/chat_llm" | ||
|
|
@@ -178,3 +181,29 @@ def rerank_config_api(req: RerankerConfigRequest): | |
| else: | ||
| res = status.HTTP_501_NOT_IMPLEMENTED | ||
| return generate_response(RAGResponse(status_code=res, message="Missing Value")) | ||
|
|
||
| @router.post("/text2gremlin", status_code=status.HTTP_200_OK) | ||
| def text2gremlin_api(req: GremlinGenerateRequest): | ||
| try: | ||
| set_graph_config(req) | ||
|
|
||
| output_types_str_list = None | ||
| if req.output_types: | ||
| output_types_str_list = [ot.value for ot in req.output_types] | ||
|
|
||
| response_dict = gremlin_generate_selective_func( | ||
| inp=req.query, | ||
| example_num=req.example_num, | ||
| schema_input=huge_settings.graph_name, | ||
| gremlin_prompt_input=req.gremlin_prompt, | ||
| requested_outputs=output_types_str_list, | ||
| ) | ||
| return response_dict | ||
| except HTTPException as e: | ||
| raise e | ||
| except Exception as e: | ||
| log.error(f"Error in text2gremlin_api: {e}") | ||
| raise HTTPException( | ||
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | ||
| detail="An unexpected error occurred during Gremlin generation.", | ||
| ) from e | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
|
|
||
| from datetime import date | ||
| from typing import Optional | ||
|
|
||
| from fastapi import status, APIRouter, HTTPException, Body | ||
|
|
||
| from hugegraph_llm.utils.log import log | ||
| from hugegraph_llm.api.models.rag_requests import GraphConfigRequest | ||
| from hugegraph_llm.config import huge_settings | ||
|
|
||
| API_CALL_TRACKER = {} | ||
|
|
||
|
|
||
| # pylint: disable=too-many-statements | ||
| def vector_http_api(router: APIRouter, update_embedding_func): | ||
| @router.post("/vector/embedding", status_code=status.HTTP_200_OK) | ||
| def update_embedding_api( | ||
| daily_limit: int = 50, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Evidence: the endpoint compares |
||
| graph_config: Optional[GraphConfigRequest] = Body(None) | ||
| ): | ||
| """ | ||
| Updates the vector embedding. | ||
| This endpoint is rate-limited. By default, it allows 2 calls per day. (Note: Not Thread-Safe!) | ||
| The rate limit is tracked per day and resets at midnight. | ||
| """ | ||
| today = date.today() | ||
| for call_date in list(API_CALL_TRACKER.keys()): | ||
| if call_date != today: | ||
| del API_CALL_TRACKER[call_date] | ||
| call_count = API_CALL_TRACKER.get(today, 0) | ||
| if call_count >= daily_limit: | ||
| log.error("Rate limit exceeded for update_vid_embedding. Maximum %d calls per day.", daily_limit) | ||
| raise HTTPException( | ||
| status_code=status.HTTP_429_TOO_MANY_REQUESTS, | ||
| detail=f"API call limit of {daily_limit} per day exceeded. Please try again tomorrow." | ||
| ) | ||
| API_CALL_TRACKER[today] = call_count + 1 | ||
| if graph_config: | ||
| huge_settings.graph_url = graph_config.url | ||
| huge_settings.graph_name = graph_config.graph | ||
| huge_settings.graph_user = graph_config.user | ||
| huge_settings.graph_pwd = graph_config.pwd | ||
| huge_settings.graph_space = graph_config.gs | ||
| huge_settings.graph_token = graph_config.token | ||
|
|
||
| result = update_embedding_func() | ||
| result = {"detail": result} | ||
| return result | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Evidence:
uv run ruff checkon the changed Python files fails withF401 huge_settings imported but unusedon this line. Since the PR currently only has the triage check on GitHub, this would be caught by the repository's normal Python quality gate later. Please remove the import and runuv run ruff checkplusuv run ruff format --checkfor the touched Python files.