File size: 14,727 Bytes
a4fab4c
c8a1c7b
c0e1a34
 
 
 
c8a1c7b
 
 
 
 
 
 
c0e1a34
 
 
 
c8a1c7b
 
c0e1a34
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0e1a34
a4fab4c
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c0e1a34
c8a1c7b
 
 
 
 
 
 
 
 
c0e1a34
 
c8a1c7b
 
 
c0e1a34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8a1c7b
 
 
c0e1a34
c8a1c7b
c0e1a34
 
c8a1c7b
 
c0e1a34
 
 
c8a1c7b
c0e1a34
 
 
 
 
 
 
c8a1c7b
c0e1a34
c8a1c7b
 
c0e1a34
 
 
 
 
 
 
 
 
 
c8a1c7b
c0e1a34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8a1c7b
1920165
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c8a1c7b
 
 
 
 
 
 
 
 
 
 
 
 
 
a4fab4c
c8a1c7b
 
 
a4fab4c
c8a1c7b
 
 
 
 
 
a4fab4c
c8a1c7b
a4fab4c
c8a1c7b
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
import gradio as gr
import cohere
import os
from dotenv import load_dotenv
from email.mime.text import MIMEText
import json
from huggingface_hub import list_models

from qdrant_client.models import Distance, VectorParams
from qdrant_client import QdrantClient, models
import uuid
import base64
import requests

load_dotenv(verbose=True)

# Initialize Qdrant and Cohere clients
client = QdrantClient(url=os.environ.get("QDRANT_URL"), api_key=os.environ.get("QDRANT_API_KEY"))
cohere_client = cohere.Client(api_key=os.environ.get("COHERE_API_KEY"))
co = cohere.ClientV2(api_key=os.environ.get("COHERE_API_KEY"))


'''# OAuthProfile example
class OAuthProfile:
    def __init__(self, name, username, profile, picture):
        self.name = name
        self.username = username
        self.profile = profile
        self.picture = picture

oauth_profile = OAuthProfile(
    name="",
    username="",
    profile="",
    picture=""
)'''


def greeting(profile: gr.OAuthProfile | None) -> str:
    if profile is None:
        return "⛔️"
    else:
        print("profile:",profile)
        state.value["loginuser"] = profile.name
        return f"ようこそ! {profile.name}さん"
    #if profile is None:
        #return "⛔️"
    #return f"ようこそ! {profile.name}さん"



def list_private_models(profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None) -> tuple[str, gr.update, gr.update]:
    gr.Textbox(oauth_token)
    if oauth_token is None:
        state.value["loginuser"] = "HuggingFaceにログインしてください。"
        state.value["picture"] = ""
        return "HuggingFaceにログインしてください。", gr.update(visible=False), gr.update(visible=False)   #, gr.update(visible=False)
    #models = [
        #f"{model.id} ({'private' if model.private else 'public'})"
        #for model in list_models(author=profile.username, token=oauth_token.token)
    #]
    userinfo = f"""名前: {profile.name}さん\nID: {profile.username}\nプロファイル: {profile.profile}"""
    print("userinfo:",userinfo)
    state.value["loginuser"] = userinfo
    state.value["picture"] = profile.picture

    print("pic:",state.value["picture"],profile.picture)
    print("login-user:",state.value["loginuser"],userinfo)

    '''global oauth_profile
    oauth_profile = OAuthProfile(
    name=profile.name,
    username=profile.username,
    profile=profile.profile,
    picture=profile.picture
    )'''
    
    #return profile.username, gr.update(visible=True), gr.update(visible=True) #, gr.update(visible=True)
    return userinfo, gr.update(visible=True), gr.update(visible=True) #, gr.update(visible=True)

def user_info(state):
    print("state:", state)
    uinfo = f"""情報: {state["loginuser"]}"""
    gr.Info(uinfo)
    #gr.Info("情報: Created by RYH International.")
    
    return gr.update(visible=True)

def auth(user_name, password):
    encoded = base64.b64encode(password.encode("utf-8"))

    # APIエンドポイントのURL
    url = "https://www.ryhintl.com/dbjson/getjson?sqlcmd=select userid from ku_credential where password = '" + encoded.decode("utf-8") + "'"

    # GETリクエストの例
    response = requests.get(url)
    if response.status_code == 200:
        credential_id = response.content.decode('utf-8')
        parsed_data = json.loads(credential_id)

        # useridを取得
        taken_userid = parsed_data[0]["userid"]
        if (taken_userid == user_name):
            state.value["loginuser"] = user_name
            return True # 認証成功
        else:
            return False

def process_invitees(state,input_json):
    try:
        # Parse the JSON input
        invitees = json.loads(input_json)

        # Generate embeddings using Cohere
        response = cohere_client.embed(
            texts=[
                f"{note.get('kx_subject', '')}, {note.get('kx_creator', '')}, {note.get('kx_content', '')}, {note.get('kx_industry', '')}, {note.get('kx_kind', '')}, {note.get('kx_category', '')}, {note.get('kx_date', '')}"
                for note in invitees
            ],
            model="embed-multilingual-v3.0",
            input_type="search_document",
        )

        # Upload points to Qdrant
        client.upload_points(
            collection_name="knowledge_utility",
            points=[
                models.PointStruct(
                    id=uuid.uuid4().hex,
                    vector=embedding,
                    payload=note,
                )
                for note, embedding in zip(invitees, response.embeddings)
            ]
        )

        return "Data uploaded successfully!"

    except Exception as e:
        return f"Error: {str(e)}"

# Function to send Gmail
def send_gmail(mail_from, mail_to, mail_subject, mail_body):
    try:
        sent_mails = f"From: {mail_from}\nTo: {mail_to}\nSubject: {mail_subject}\nBody:\n{mail_body}\n"
    except Exception as e:
        sent_mails = f"Error sending mail: {str(e)}"
    return sent_mails

# Function to handle search query
def search(state,query: str):
    #state["userid"] = "kuuser"
    
    global sent_mails
    # Embed query using Cohere
    response = cohere_client.embed(
        texts=[query],
        model="embed-multilingual-v3.0",
        input_type="search_query",
    )
    
    # Query Qdrant collection for relevant points
    results = client.query_points(
        collection_name="knowledge_utility",
        query=response.embeddings[0],
        limit=1,
    ).points

    for result in results:
        state["score"] = result.score
        
    # Filter points based on similarity threshold
    similarity_threshold = 0.1  # Example threshold for filtering
    filtered_points = [point for point in results if point.score >= similarity_threshold]

    #print("filtered_points:",filtered_points)

    # Apply limit to the filtered points
    final_limit = len(filtered_points)  # Example limit
    limited_points = filtered_points[:final_limit]
    #print("finals:",final_limit,limited_points)

    # Assuming `results` is a list of ScoredPoint objects
    payload_list = []

    # Iterate through the limited results and extract payloads
    for point in limited_points:
        # Access the payload attribute and append it to the list
        #print("point:",point)
        payload_list.append(point.payload)
    
    #print("payload_list:",payload_list)

    # Template for the invitation letter
    template = ""

    # Prepare results in a user-friendly format
    formatted_results = [
        f"kx_subject: {point.payload['kx_subject']}\nkx_content: {point.payload['kx_content']}\nkx_creator: {point.payload['kx_creator']}\nkx_industry: {point.payload['kx_industry']}\nkx_kind: {point.payload['kx_kind']}\nkx_category: {point.payload['kx_category']}\nkx_date: {point.payload['kx_date']}"
        for point in results
    ]

    #print("formatted_results",formatted_results)
    final_result = "\n\n".join(formatted_results)

    res = co.chat(
    model="command-a-03-2025",
    messages=[
        {
            "role": "user",
            "content": final_result+"を要約してください。 必ず、日本語で答えてください。",
        }
    ],
    )
    final = res.message.content[0].text

    # Extract content between "---"
    start_marker = "---"
    end_marker = "---"
    start_index = final.find(start_marker) + len(start_marker)
    end_index = final.rfind(end_marker)

    return final,state["score"]

# Gradio Blocks Interface
with gr.Blocks(css="footer {visibility: hidden;} .custom-image {width: 64px; height: 64px;} .custom-btn {width: 150px; height: 30px; background-color: lightblue; border-radius: 10px; font-size: 12px; color: #3C82F6;} #header {display: flex; justify-content: space-between; align-items: center; font-size: 24px; font-weight: bold;} #logo {width: 50px; height: 50px;}",title="Knowledge Utility",theme=gr.themes.Glass()) as ku:
    state = gr.State({
        "userid": "",
        "loginuser": "",
        "picture": "",
        "score": 0
    })
    
    gr.LoginButton()
    # ^ add a login button to the Space
    m1 = gr.Markdown()
    m2 = gr.Markdown()
    ku.load(greeting, inputs=None, outputs=m1)

    with gr.Column():
        gr.HTML('<div id="header"><span>🛡️ Knowledge Utility</span><img id="logo" src="https://www.ryhintl.com/images/ryhlogo/ryhlogo.png" width="64" height="64" alt="Logo"></div>')
        gr.Markdown("# ナレッジ・エージェント")
        gr.Markdown("📧 ベクターDBに保存されている知識ベースのインベントリを使用して知識共有します。")
        

    with gr.Sidebar(open=False):
        #gr.Image(value=oauth_profile.picture, elem_classes=["custom-image"])
        
        gr.HTML("""
        <!DOCTYPE html>
        <html lang="ja">
        <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Knowledge Utility</title>
        <style>
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            background-color: #f4f4f9;
            color: #333;
            margin: 0;
            padding: 0;
        }
        header {
            background: #0078d7;
            color: #fff;
            padding: 1rem 0;
            text-align: center;
        }
        section {
            max-width: 800px;
            margin: 2rem auto;
            padding: 1rem;
            background: #fff;
            border-radius: 5px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
        h1, h2, h3 {
            color: #0078d7;
        }
        ul {
            padding-left: 1.5rem;
        }
        footer {
            text-align: center;
            padding: 1rem 0;
            margin-top: 2rem;
            background: #0078d7;
            color: white;
        }
        </style>
        </head>
        <body>
        <header>
            <h1 style="color: white;">Knowledge Utility</h1>
            <p style="color: white;">知識をシェアし、成長を加速させる。</p>
        </header>
        <section>
            <h2>Knowledge Utilityとは?</h2>
            <p>
                Knowledge Utilityは、企業や個人が知識を効果的に共有し、成長を促進するためのプラットフォームです。
                データ、アイデア、専門知識をシームレスに交換し、新たな価値を生み出します。
            </p>
        <h2>主な機能</h2>
        <ul>
            <li><strong>情報の検索:</strong> 高速かつ正確なクエリによる知識の取得。</li>
            <li><strong>データの登録:</strong> 個人または企業の資産をデータベースに統合。</li>
            <li><strong>コラボレーション:</strong> チームやコミュニティ間の知識交換を促進。</li>
        </ul>
        <h2>メリット</h2>
        <p>
            Knowledge Utilityを活用することで、効率の向上、意思決定のスピードアップ、そして
            組織の成長が期待できます。
        </p>
        </section>
        <footer>
            <p>&copy; 2025 Knowledge Utility Platform. All rights reserved.</p>
        </footer>
        </body>
        </html>
    """)

        with gr.Blocks(css=".custom-btn-container { display: flex; justify-content: center; } .custom-btn { width: 150px; height: 30px; background-color: lightblue; border-radius: 10px; font-size: 12px; color: #3C82F6; }") as ubutton:
            with gr.Row(elem_classes=["custom-btn-container"]): # 中央揃え用のクラス
                user_btn = gr.Button("情報", elem_classes=["custom-btn"])
                user_btn.click(fn=user_info, inputs=[state], outputs=user_btn)

        #user_btn = gr.Button("情報", elem_classes=["custom-btn"])

    #user_btn.click(fn=user_info, inputs=[state], outputs=None)
        

    with gr.Tab("KU 検索") as tab_find:
        with gr.Row():
            query_input = gr.Textbox(
                label="クエリ",
                placeholder="例)物流・流通業界向けの提案書を内容を教えてください。",
                info="例)物流・流通業界向けの提案書を内容を教えてください。AI市場の動向を調べています。参考できる事例を教えてください。", 
                value="経営デジタル・トランスフォーメーション関連のプロジェクトの提案書を書こうと思っています。参考できる事例を教えてください。",
                lines=2,
            )
            with gr.Column():
                search_button = gr.Button("実行", elem_classes=["custom-btn"])
                clear_button = gr.Button("クリア", elem_classes=["custom-btn"])
    
        result_output = [gr.Textbox(label="結果", show_copy_button=True),gr.Textbox(label="スコア")]

        # Button click events
        search_button.click(fn=search, inputs=[state,query_input], outputs=result_output)
        clear_button.click(lambda: "", None, result_output)

    with gr.Tab("KU インベントリ登録") as tab_reg:
        with gr.Row():
            input_text = gr.Textbox(label="KU JSON Payroll", lines=10, placeholder="Paste your JSON Payroll here...", info="""[{"kx_subject": "中古車販売における現状と問題点", "kx_creator": "username", "kx_content": "事前情報の収集: 顧客動向、問題・課題の想定、3C分析を通じて仮説を策定する。企業動向、顧客動向、競合動向を分析し、仮説を立案する。仮説提案営業の商談フロー: あいさつ、自社紹介、詳細ヒアリング、仮説検証、解決策の提案、ディスカッション、宿題の出し合い、あいさつのステップを踏む。効果的な商談の進め方: 訪問の趣旨を伝え、基本的な質問をし、相手に話させる。仮説をぶつけ、次回の日付と宿題を決める。ヒアリングの技術: 荷主担当者と営業担当者の知識の差を理解し、必要に応じて役割を分担する。ロジスティクスフローを描き、詳細な設問項目を作成する。", "kx_industry": "物流・流通", "kx_kind": "小売", "kx_category": "提案書", "kx_date": "2025/06/02"}]""")
            output_text = gr.Textbox(label="Result")
        with gr.Row():
            submit_button = gr.Button("実行", elem_classes=["custom-btn"])

        submit_button.click(process_invitees, inputs=[state,input_text], outputs=output_text)

# Launch the app
    ku.load(list_private_models, inputs=None, outputs=[m2, tab_find, tab_reg])
ku.launch(favicon_path="favicon.ico",share=True)