File size: 8,632 Bytes
2529adf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3596a9a
2529adf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import requests
import json
from duckduckgo_search import DDGS
import re
import clipboard
import io
import os
import pandas as pd
from PyPDF2 import PdfFileReader
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import tiktoken
from langchain import LLMChain, PromptTemplate

# OpenRouter APIキーの設定
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY").strip()

# Streamlitアプリケーションの設定
st.set_page_config(page_title="Orb AI", page_icon="🤖", layout="wide")

# セッション状態の初期化
if 'messages' not in st.session_state:
    st.session_state.messages = []
if 'uploaded_file_content' not in st.session_state:
    st.session_state.uploaded_file_content = None

def read_pdf(file):
    pdf = PdfFileReader(file)
    content = ""
    for page_num in range(pdf.getNumPages()):
        page = pdf.getPage(page_num)
        content += page.extract_text()
    return content

def read_csv(file):
    df = pd.read_csv(file)
    return df.to_string()

def read_image(file):
    image = Image.open(file)
    text = pytesseract.image_to_string(image)
    return text

def fetch_webpage_text(url):
    response = requests.get(url)
    if response.status_code != 200:
        return "Web page could not be retrieved"
    soup = BeautifulSoup(response.text, 'html.parser')
    paragraphs = soup.find_all('p')
    text_content = ' '.join([paragraph.get_text() for paragraph in paragraphs])
    return text_content

def truncate_prompt(prompt, max_tokens):
    tokenizer = tiktoken.get_encoding("cl100k_base")
    tokens = tokenizer.encode(prompt)
    if len(tokens) > max_tokens:
        truncated_tokens = tokens[:max_tokens]
        truncated_prompt = tokenizer.decode(truncated_tokens)
        return truncated_prompt
    return prompt

def call_openrouter_api(prompt, model):
    max_context_tokens = 4096
    completion_tokens = 500
    max_prompt_tokens = max_context_tokens - completion_tokens
    truncated_prompt = truncate_prompt(prompt, max_prompt_tokens)
    response = requests.post(
        url="https://openrouter.ai/api/v1/chat/completions",
        headers={
            "Authorization": f"Bearer {OPENROUTER_API_KEY}",
            "HTTP-Referer": "https://supertakerin2-comcomgptfree.hf.space/",
            "X-Title": "Orb AI",
        },
        data=json.dumps({
            "model": model,
            "messages": [{"role": "user", "content": truncated_prompt}]
        })
    )
    if response.status_code == 200:
        try:
            response_json = response.json()
            if "choices" in response_json:
                return response_json["choices"][0]["message"]["content"]
            else:
                st.error("API response does not contain 'choices'")
                return "API response does not contain 'choices'"
        except json.JSONDecodeError:
            st.error("API response JSON decoding failed.")
            return "API response JSON decoding failed."
    else:
        st.error(f"API request failed status code: {response.status_code}, message: {response.text}")
        return "API request failed"

# サイドバーにAIモデルの選択、モード選択、ファイルアップロードを配置
with st.sidebar:
    ai_model = st.selectbox(
        "Select AI model",
        ["openchat/openchat-7b:free", "microsoft/phi-3-mini-128k-instruct:free", "meta-llama/llama-3.1-8b-instruct:free", "google/gemma-7b-it:free", "undi95/toppy-m-7b:free", "mistralai/mistral-7b-instruct:free"],
        key="model_select"
    )
    mode = st.selectbox(
        "Select mode",
        ["focus", "writing", "video", "summary"],
        key="mode_select"
    )
    # ファイルアップロード機能をサイドバーに移動
    uploaded_file = st.file_uploader("Upload file", type=["txt", "pdf", "csv", "py", "html", "css", "js", "cs", "php", "java", "jpg"])
    if uploaded_file is not None:
        file_extension = uploaded_file.name.split('.')[-1].lower()
        if file_extension in ['txt', 'py', 'html', 'css', 'js', 'cs', 'php', 'java']:
            stringio = io.StringIO(uploaded_file.getvalue().decode("utf-8"))
            st.session_state.uploaded_file_content = stringio.read()
        elif file_extension == 'pdf':
            st.session_state.uploaded_file_content = read_pdf(uploaded_file)
        elif file_extension == 'csv':
            st.session_state.uploaded_file_content = read_csv(uploaded_file)
        elif file_extension in ['jpg']:
            st.session_state.uploaded_file_content = read_image(uploaded_file)
        st.success(f"file '{uploaded_file.name}' was uploaded")

    # 会話をクリアするボタン
    if st.button("🔥 Delete conversation"):
        st.session_state.messages = []
        st.session_state.uploaded_file_content = None

# メインコンテンツ
st.title("Orb AI")

# チャット履歴の表示
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# ユーザー入力
if prompt := st.chat_input("Please enter your message."):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    # アップロードされたファイルの内容を考慮してプロンプトを作成
    if st.session_state.uploaded_file_content:
        prompt = f"以下のファイル内容を参考にして回答してください:\n\n{st.session_state.uploaded_file_content}\n\nユーザーの質問: {prompt}"

    full_response = ""

    if mode == "focus":
        # DuckDuckGo検索の実行
        with DDGS() as ddgs:
            search_results = list(ddgs.text(prompt, max_results=4))
            search_results_text = "\n".join([result["body"] for result in search_results])
            urls = "\n".join([result["href"] for result in search_results[:4]])
            prompt = f"質問: {prompt}\n\n検索結果: {search_results_text}\n\n上記の情報に基づいて、詳細な回答を提供してください:"
            full_response = call_openrouter_api(prompt, ai_model)
            # 回答の下に検索結果のURLを表示
            with st.chat_message("assistant"):
                st.markdown(full_response)
                st.markdown("### Sources:")
                st.markdown(urls)
            
    elif mode == "writing":
        prompt = f"次のトピックについて包括的な記事を書いてください: {prompt}\n\n導入、主要なポイント、および結論を含めてください。"
        full_response = call_openrouter_api(prompt, ai_model)
        with st.chat_message("assistant"):
            st.markdown(full_response)
        
    elif mode == "summary":
        prompt = f"次のテキストを簡潔に要約してください:\n\n{prompt}\n\n主要なポイントを捉えた簡潔な要約を提供してください。"
        full_response = call_openrouter_api(prompt, ai_model)
        with st.chat_message("assistant"):
            st.markdown(full_response)
        
    elif mode == "video":
        # DuckDuckGo検索を使用してYouTubeの動画を検索
        with DDGS() as ddgs:
            search_results = list(ddgs.text(f"{prompt} site:youtube.com", max_results=5))
            if search_results:
                for result in search_results[:4]:
                    video_url = result['href']
                    video_id = None
                    youtube_patterns = [
                        r"(?<=v=)[^/]+",
                        r"(?<=be/)[^/]+",
                        r"(?<=embed/)[^/]+"
                    ]
                    for pattern in youtube_patterns:
                        match = re.search(pattern, video_url)
                        if match:
                            video_id = match.group()
                            break
                    if video_id:
                        st.markdown(f'<iframe width="560" height="315" src="https://www.youtube.com/embed/{video_id}" frameborder="0" allowfullscreen></iframe>', unsafe_allow_html=True)
                        st.markdown(f"Related Videos: {result['title']}")
                    else:
                        st.warning(f"Video ID not found: {video_url}")
            else:
                full_response = "No related videos were found."
                with st.chat_message("assistant"):
                    st.markdown(full_response)

    # コピー機能の追加
    if st.button("📋 Copy the generated text"):
        clipboard.copy(full_response)
        st.success("Text has been copied to the clipboard!")