Coverage for app/endpoint/knowledge/create_knowledge.py: 40%
53 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-16 01:07 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-16 01:07 +0000
1from app.endpoint.knowledge.router import router
2from app.infrastructure.database.db import get_session
4from fastapi import Depends
5from sqlmodel import Session
7# ========== 埋め込み関数 ==========
8from ollama import Client
9OLLAMA_URL = "http://host.docker.internal:11434"
10OLLAMA_EMMBEDDING_MODEL = "zylonai/multilingual-e5-large:latest"
11OLLAMA_LLM_MODEL = "llama3:latest"
12def get_embedding(text: str):
13 # ollamaクライアント
14 client = Client(host=OLLAMA_URL)
15 # emb実行
16 result = client.embed(model=OLLAMA_EMMBEDDING_MODEL, input=text)
17 return result
19# ========== 簡易グラフ変換関数 ==========
20import json
21def get_graph_by_manual(text: str):
22 """
23 非LLMなルールベース処理。
24 例文:「田中さんはABC株式会社でエンジニアをしています。」
25 """
26 if "は" in text and "で" in text:
27 person = text.split("は")[0].strip()
28 company = text.split("は")[-1].split("で")[0].strip()
29 role = text.split("で")[-1].replace("をしています", "").replace("として働いています", "").strip("。")
30 return {"person": person, "company": company, "role": role}
31 return None
33def get_graph_by_ollama(text: str):
34 prompt = f"""
35あなたは自然文を構造化するAIアシスタントです。
36以下の日本語文を、グラフ構造としてノードとリレーションに分解してください。
38出力形式は JSON としてください。形式は以下の通りです。
39**必ずこの形式で返してください。余計な文章や説明は一切入れないでください。**
41{{
42 "nodes": [{{"id": "名前", "label": "ラベル"}}],
43 "relationships": [{{"from": "ノードID", "to": "ノードID", "type": "リレーションタイプ", "properties": {{}} }}]
44}}
46入力文:
47{text}
48"""
49 # ollamaクライアント
50 client = Client(host=OLLAMA_URL)
51 response = client.generate(
52 model=OLLAMA_LLM_MODEL,
53 prompt=prompt
54 )
56 print(response['response'])
57 # 応答を JSON にパース
58 try:
59 result = json.loads(response['response'])
61 except json.JSONDecodeError:
62 raise ValueError("Ollamaからの応答をJSONとして解析できませんでした:\n" + response['response'])
64 return result
66# neo4j登録
67from neo4j import GraphDatabase
68NEO4J_URI = "bolt://search:7687"
69NEO4J_USER = "neo4j"
70NEO4J_PASS = "password"
72def register_graph(graph_data, text, embedding):
73 driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASS))
74 with driver.session() as session:
75 for node in graph_data.get("nodes", []):
76 props = {
77 "id": node["id"],
78 "text": text,
79 "embedding": embedding,
80 }
81 label = node.get("label", "Entity")
82 session.run(
83 f"""
84 MERGE (n:{label} {{id: $id}})
85 SET n.text = $text,
86 n.embedding = $embedding
87 """,
88 **props
89 )
91 for rel in graph_data.get("relationships", []):
92 session.run(
93 f"""
94 MATCH (a {{id: $_from}})
95 MATCH (b {{id: $to}})
96 MERGE (a)-[r:{rel["type"]}]->(b)
97 SET r += $props
98 """,
99 _from=rel["from"],
100 to=rel["to"],
101 props=rel.get("properties", {})
102 )
104from sqlmodel import SQLModel
105class CreateKnowledgeRequest(SQLModel):
106 text: str
108@router.post(
109 "/knowledges"
110)
111async def create_knowledge(
112 request: CreateKnowledgeRequest,
113 session: Session = Depends(get_session),
114):
115 text = request.text
116 print(text)
117 embedding = get_embedding(text)['embeddings'][0]
118 graph = get_graph_by_ollama(text)
119 # person, company, role = graph["person"], graph["company"], graph["role"]
121 # 3. Neo4j にノード+リレーション登録
122 register_graph(graph, text, embedding)
125 return {
126 "graph": graph,
127 "text": text,
128 # "neo4j": {
129 # "person": person,
130 # "company": company,
131 # "role": role
132 # },
133 "embedding": embedding,
134 }