Repository navigation
Expand file tree
/
Copy pathopenai_chat.py
More file actions
193 lines (168 loc) · 7.1 KB
/
Copy pathopenai_chat.py
File metadata and controls
193 lines (168 loc) · 7.1 KB
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
import os
import openai
from openai import OpenAI
from openai import AsyncOpenAI
import asyncio
# ローカル LLM モジュール(--local-llm 時のみ利用)
try:
import local_llm as _local_llm_mod
except ImportError:
_local_llm_mod = None # type: ignore[assignment]
# OpenAI APIから応答を取得する関数 ログなし(非同期版)
async def chat_req(
client,
user_msg,
role,
model: str | None = None,
max_tokens: int | None = None,
temperature: float | None = None,
repeat_penalty: float | None = None,
):
# ローカル LLM がロード済みなら直接呼び出す(client は使わない)
if _local_llm_mod is not None and _local_llm_mod.is_loaded():
loop = asyncio.get_running_loop()
return await loop.run_in_executor(
None,
lambda: _local_llm_mod.chat_completion(
user_msg=user_msg,
role=role,
max_tokens=max_tokens,
temperature=temperature,
repeat_penalty=repeat_penalty,
),
)
messages = [
{"role": "system", "content": role},
{"role": "user", "content": user_msg}
]
# await を使って coroutine の実行結果を取得
effective_model = (model or os.environ.get("OPENAI_CHAT_MODEL") or "gemma3:latest")
kwargs = {}
if max_tokens is not None:
kwargs["max_tokens"] = max_tokens
if temperature is not None:
kwargs["temperature"] = temperature
# repeat_penalty: llama.cpp と Ollama 両方でサポート
# extra_body 経由で渡すことで未対応バックエンドでも 400 にならない
if repeat_penalty is not None:
kwargs["extra_body"] = {"repeat_penalty": repeat_penalty}
completion = await client.chat.completions.create(
model=effective_model,
messages=messages,
**kwargs,
)
return completion.choices[0].message.content
# VLM(Vision Language Model)用の関数 - 画像付きチャット(非同期版)
async def vlm_req(client, user_msg, image_base64, role="You are a helpful assistant.", model="gemma-3-27b-it", max_tokens=1024, temperature=0.3):
"""
画像付きのチャットリクエストを送信する
Args:
client: AsyncOpenAI client
user_msg: ユーザーのテキスト入力
image_base64: Base64エンコードされた画像("data:image/jpeg;base64,..." 形式)
role: システムロール
model: 使用するモデル名
max_tokens: 最大トークン数
temperature: 温度パラメータ
Returns:
str: モデルの応答テキスト
"""
messages = [
{"role": "system", "content": role},
{
"role": "user",
"content": [
{"type": "text", "text": user_msg},
{"type": "image_url", "image_url": {"url": image_base64}}
]
}
]
completion = await client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
)
return completion.choices[0].message.content
# VLM(Vision Language Model)用の関数 - 複数画像対応(非同期版)
async def vlm_req_multi_images(client, user_msg, images_base64, role="You are a helpful assistant.", model="gemma-3-27b-it", max_tokens=1024, temperature=0.3):
"""
複数画像付きのチャットリクエストを送信する
Args:
client: AsyncOpenAI client
user_msg: ユーザーのテキスト入力
images_base64: Base64エンコードされた画像のリスト
role: システムロール
model: 使用するモデル名
max_tokens: 最大トークン数
temperature: 温度パラメータ
Returns:
str: モデルの応答テキスト
"""
content = [{"type": "text", "text": user_msg}]
for img in images_base64:
content.append({"type": "image_url", "image_url": {"url": img}})
messages = [
{"role": "system", "content": role},
{"role": "user", "content": content}
]
completion = await client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
)
return completion.choices[0].message.content
# OpenAI APIから応答を取得する関数
def chat_conversation(client,user_msg,role,conversation_logs,max_logs):
# ステップ1: ユーザー入力と関数の定義を GPT に送る
messages = [{"role": "system", "content": role}] + conversation_logs + [{"role": "user", "content": user_msg}]
completion = client.chat.completions.create(
model="gemma2:latest",
messages=messages,
#stream=True,
)
out1=completion.choices[0].message.content
print("put1=",out1)
conversation_logs.append({"role": "user", "content": user_msg})
conversation_logs.append({"role": "assistant", "content": out1})
# 会話ログが最大数を超えた場合、古いログを削除
if len(conversation_logs) > max_logs:
conversation_logs = conversation_logs[-max_logs:]
return out1,conversation_logs
# OpenAI APIから応答を取得する非同期ジェネレーター関数
#async def chat_with_openai_stream(a_client, user_message,role, conversation_logs, max_logs):
async def chat_with_openai_stream(a_client, user_message,role, conversation_logs):
try:
# 会話履歴にroleとユーザーメッセージを追加
messages = [{"role": "system", "content": role}] + conversation_logs + [{"role": "user", "content": user_message}]
#messages = [{"role": "system", "content": "Reasoning: low"+role+"、必ず日本語で答える"}] + conversation_logs + [{"role": "user", "content": user_message}]
# デバッグ用のメッセージ出力
#print(f"Sending to API: {messages}")
# ストリーミングリクエストを実行
stream = await a_client.chat.completions.create(
model="gpt-4",
messages=messages,
#extra_body={"chat_template_kwargs":{"reasoning_effort": "low"}},
stream=True,
)
response_sum = ""
# ストリーミングで応答を処理
async for chunk in stream:
response_chunk = chunk.choices[0].delta.content or ""
response_sum += response_chunk
#print(response_sum)
yield response_chunk # 部分的な応答をストリーミング
'''
# 全体の応答を保存
conversation_logs.append({"role": "user", "content": user_message})
conversation_logs.append({"role": "assistant", "content": response_sum})
# 会話ログが最大数を超えた場合、古いログを削除
if len(conversation_logs) > max_logs:
print("****MAX_log***")
conversation_logs = conversation_logs[-max_logs:]
print("conversation_logs len=",len(conversation_logs))
print(conversation_logs)
'''
except Exception as e:
yield f"Error: {str(e)}"